AngularJS: Radio buttons do not work with Bootstra

2019-02-06 01:17发布

问题:

I have a radio button, which sets the value of True or False based on the value of transaction type

The demo can be found here

The problem is when I click on any of the radio button, the value of $scope.transaction.debit does not change

My javascript code is

    var app = angular.module('myApp', []);

    app.controller("MainCtrl", function($scope){
      $scope.transaction = {};
      $scope.transaction.debit=undefined;

      console.log('controller initialized');
    });

Please let me know what I am doing wrong.

Also, I do not want to use Angular-UI or AngularStrap for this purpose, unless no other option is available.

回答1:

You have a large label stuck over the top of the radio buttons which prevents input to your radio buttons. The html should read:

 <input type="radio" data-ng-model="transaction.debit" value="True">Debit</input>

 <input type="radio" data-ng-model="transaction.debit" value="False">Credit</input>

It then works, of course it may not look the way you want it to then.



回答2:

I modified dpineda's solution. You can use without removing bootsrap.js dependency. Also there is a working example here.

This is the flow:

  1. Remove data-toggle="buttons" for preventing bootstrap execution.
  2. Add some CSS for fixing the broken view (btn-radio css class)
  3. Add some AngularJS logic for checked style effect.

html

<div class="btn-group col-lg-3">
  <label class="btn btn-default btn-radio" ng-class="{'active': transaction.debit == '0'}">
    <input type="radio" data-ng-model="transaction.debit" value="0"> Debit
  </label>
  <label class="btn btn-default btn-radio" ng-class="{'active': transaction.debit == '1'}">
    <input type="radio" data-ng-model="transaction.debit" value="1"> Credit
  </label>
</div>

<p>Transaction type: {{transaction.debit}}</p>

JavaScript

var app = angular.module('myApp', []);

app.controller("MainCtrl", function($scope) {

  $scope.transaction = {
    debit: 0
  };
});

Style

.btn-radio > input[type=radio] {
  position       : absolute;
  clip           : rect(0, 0, 0, 0);
  pointer-events : none;
}


回答3:

I found the problem in bootstrap.js. Comment the line e.preventDefault(), it works.

// BUTTON DATA-API
// ===============
$(document)
.on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
    var $btn = $(e.target)
    if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
    Plugin.call($btn, 'toggle')
    e.preventDefault() //Before
    //e.preventDefault() //After
})
.on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
    $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
})


回答4:

if you remove de bootstrap code you can control the styles with conditionals

<label class="btn btn-default" ng-class="{'active': transaction.debit == 'some'}">
    <input type="radio" data-ng-model="transaction.debit" name="debit" value="some"> Some
</label>
<label class="btn btn-default" ng-class="{'active': transaction.debit == 'other'}">
    <input type="radio" data-ng-model="transaction.debit" name="debit" value="other"> Other
</label>


回答5:

Here's a working version using a new directive:

html

<section ng-controller="MainCtrl">
<div class="form-group">
    <label class="col-lg-2 control-label">Type</label>

    <div class="btn-group col-lg-3" data-toggle="buttons">
        <label class="btn btn-default" radio-button ng-model="transaction.debit" value="True">
            Debit
        </label>
        <label class="btn btn-default" radio-button ng-model="transaction.debit" value="False">
            Credit
        </label>
    </div>

    <p>Transaction type: {{transaction.debit}}</p>
</div>
</section>

javascript

// Code goes here
var app = angular.module('myApp', []);

app.controller("MainCtrl", function($scope){
  $scope.transaction = {};
  $scope.transaction.debit=undefined;

  console.log('controller initialized');
});

app.directive("radioButton", function() {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, element, attrs, ctrl) {
      element.bind('click', function () {
        if (!element.hasClass('active')) {
          scope.$apply(function () {
            scope.transaction.debit = attrs.value;
          });
        }
      });
    }
  };
})


回答6:

Based on francisco.preller's answer I wrote two solutions trying to make it fit for generic use, without loosing the input tags: html:

        <label class="btn btn-info" radiobuttonlbl>
          <input ng-model="query.gender" type="radio" value="0">male
        </label>

solution #1:

.directive("radiobuttonlbl", function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs, ctrl) {
      element.bind('click', function () {
        var input_elem = angular.element(element.find('input')[0]);
        (function(o, s, v) {
          s = s.replace(/\[(\w+)\]/g, '.$1');
          s = s.replace(/^\./, '');
          var a = s.split('.').reverse();
          while(a.length>1) {
            var k = a.pop();
            o = o[k];
          }
          scope.$apply(function(){ o[a.pop()]=v;});
        })(scope, input_elem.attr('ng-model'), input_elem.attr('value'));
      });
    }
  };
})

Solution #2:

.directive("radiobuttonlbl", function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs, ctrl) {
      element.bind('click', function () {
        var input_elem = angular.element(element.find('input')[0]);
        input_elem.prop('checked',true);
        input_elem.triggerHandler('click'); 
      });
    }
  };
})

I have a feeling the first one is better because it make angular do the updating work.



回答7:

I have the same problem, in my case, the default style change and can't use angular ng-model inside any radio or checkbox button. So i read some articles and found that sometimes if you load JQuery after Bootstrap it overwrites something and it prevent default styles and components to be loaded as bootstrap components, this also happens if you load angularJS after jQuery or viceversa.

PS.- My answer: Check your load script stack, play with it and find which order works for you. (first jquery, then angularJs, finally bootstrap).



回答8:

I had the same problem. Use ng-click on your labels and it will work fine with bootstrap

<label class="btn btn-default" ng-click="transaction.debit = 'debit'">

Here it's working in plunker