AngularJS:使用Bootstrap 3时单选按钮无法工作

16

我有一个单选按钮,根据交易类型的值设置TrueFalse的值。

演示可以在这里找到。

问题是当我点击任何一个单选按钮时,$scope.transaction.debit的值不会改变。

我的JavaScript代码如下:

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

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

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

请告诉我我做错了什么。

此外,除非没有其他选择,否则我不想使用Angular-UIAngularStrap来实现这个目的。


1
你是对的。移除围绕单选按钮的引导代码可以使它们再次工作。我怀疑单选按钮实际上由于引导而未被选择?请注意,即使有工作的CSS,移除对bootstrap.js文件的脚本引用也可以使它们再次工作。 - francisco.preller
您也可以寻找类似的问题(Angular-Strap Radio Button won't update model)。虽然它涉及到库的冲突,主要是指bootstrap3 + angular-strap,但是有人(或者将来的您)可能会寻找它。 - Egel
9个回答

11

我修改了dpineda的解决方案。你可以在不移除bootstrap.js依赖的情况下使用它。同时,在这里有一个可工作的示例。

以下是操作流程:

  1. 删除data-toggle="buttons"以防止bootstrap执行。
  2. 添加一些CSS来修复损坏的视图(btn-radio css类)
  3. 添加一些AngularJS逻辑以实现选中效果。

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
  };
});

样式

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

我发现关键问题是删除data-toggle="buttons"以禁用bootstrap.js的功能,然后添加上述样式来弥补实际单选按钮的重新出现。 - Lee H
我在Angular 6中仍然遇到了这个问题,通过删除data-toggle="buttons"并在每个标签中添加[class.active]="option == 'value'"来解决了这个问题。我不需要进行任何CSS更改。 - Burhan

5

我发现问题出在 bootstrap.js 上。将这行代码 e.preventDefault() 注释掉,问题就解决了。

// 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))
})

2

你的单选按钮上方有一个大标签,它阻止了对单选按钮的输入。

正确的html应该是:

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

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

当然,它可以正常工作,但可能不会以您想要的方式呈现。

3
删除bootstrap.js文件可以解决问题,这让我相信它与标签无关,而更多地与bootstrap注入的javascript有关。同时,删除标签当然会停止Bootstrap JavaScript在这些对象上的运行。 - francisco.preller
6
另一种选择是在标签上使用ng-click来处理点击和数据交互,这样就不必移除bootstrap的javascript。http://plnkr.co/edit/8i86U2?p=preview - user2789093
这个链接解释了如何使用Bootstrap和Angular:https://scotch.io/tutorials/how-to-correctly-use-bootstrapjs-and-angularjs-together - Chocksmith
即使是 Plunker 也在关于这个错误的 </input> 结束标签进行代码检查。这怎么成为一个被选中的答案了呢? - Vladius

2
如果您删除Bootstrap代码,您可以使用条件语句来控制样式。
<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>

1

根据francisco.preller的答案,我写了两个解决方案,试图使其适用于通用情况,而不会丢失输入标记:

html:

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

解决方案 #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'));
      });
    }
  };
})

解决方案 #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'); 
      });
    }
  };
})

我有一种感觉,第一个更好,因为它让Angular完成更新工作。

这个答案不是最理想的,但是在这一页上是最好的一个。 - A1rPun

1
这里是使用新指令的可用版本: 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;
          });
        }
      });
    }
  };
})

该指令过于具体。使用您的解决方案会失去引导功能。.debit=undefined根本没有起到任何作用。-1 - A1rPun

0

如果有人仍在寻找一种简单的方法来实现这个(我个人不愿意用指令过度加载我的代码),这是我所做的:

您可以使用标签上的ng-click设置值。此外,请注意第一个单选按钮标签上的ng-initactive类。这样,您可以让Bootstrap和Angular各自发挥作用。唯一的缺点是您没有使用ng-model让Angular控制它。

<div class="btn-group col-lg-3" data-toggle="buttons">
      <label class="btn btn-default active" ng-init="transaction.debit=true" ng-click="transaction.debit=true">
        <input type="radio" checked> Debit
      </label>
      <label class="btn btn-default" ng-click="transaction.debit=false">
        <input type="radio"> Credit
      </label>
    </div>

-1

我有同样的问题,在我的情况下,默认样式更改,无法在任何单选框或复选框按钮中使用angular ng-model。所以我阅读了一些文章,并发现有时如果您在Bootstrap之后加载JQuery,则会覆盖jQuery的任何其他实例,并且它会防止默认样式和组件作为Bootstrap组件加载,如果您在jQuery之后或反之亦然加载angularJS也会发生这种情况。

PS.- 我的答案:检查您的加载脚本堆栈,尝试并找到适合您的顺序(首先是jquery,然后是angularJs,最后是bootstrap)。通常,您需要将jQuery作为第一个选项,Angular和几乎所有新框架都在其之上运行。干杯。


1
太好了,问题找到了。我把bootstrap.min.js在jquery.min.js之前加载,问题完全消失了!谢谢。 - Nabeel
2
不幸的是,这解决了特定的问题,但由于jQuery是Bootstrap的依赖项,因此破坏了其他所有内容。 - Nabeel

-1

我曾经遇到过同样的问题。在标签上使用ng-click,就可以很好地与Bootstrap配合使用。

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

在这里它在 Plunker 上运行正常


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接