我有一些复选框:

<input type='checkbox' value="apple" checked>
<input type='checkbox' value="orange">
<input type='checkbox' value="pear" checked>
<input type='checkbox' value="naartjie">

我想绑定到我的控制器中的一个列表,这样每当一个复选框被更改时,控制器就会维护一个包含所有选中值的列表,例如,['apple', 'pear']。

Ng-model似乎只能将一个复选框的值绑定到控制器中的一个变量。

是否有其他方法可以将这四个复选框绑定到控制器中的列表?


当前回答

灵感来自Yoshi上面的帖子。 这是钱。

(function () { angular .module("APP", []) .controller("demoCtrl", ["$scope", function ($scope) { var dc = this dc.list = [ "Selection1", "Selection2", "Selection3" ] dc.multipleSelections = [] dc.individualSelections = [] // Using splice and push methods to make use of // the same "selections" object passed by reference to the // addOrRemove function as using "selections = []" // creates a new object within the scope of the // function which doesn't help in two way binding. dc.addOrRemove = function (selectedItems, item, isMultiple) { var itemIndex = selectedItems.indexOf(item) var isPresent = (itemIndex > -1) if (isMultiple) { if (isPresent) { selectedItems.splice(itemIndex, 1) } else { selectedItems.push(item) } } else { if (isPresent) { selectedItems.splice(0, 1) } else { selectedItems.splice(0, 1, item) } } } }]) })() label { display: block; } <!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css" /> </head> <body ng-app="APP" ng-controller="demoCtrl as dc"> <h1>checkbox-select demo</h1> <h4>Multiple Selections</h4> <label ng-repeat="thing in dc.list"> <input type="checkbox" ng-checked="dc.multipleSelections.indexOf(thing) > -1" ng-click="dc.addOrRemove(dc.multipleSelections, thing, true)" > {{thing}} </label> <p> dc.multipleSelections :- {{dc.multipleSelections}} </p> <hr> <h4>Individual Selections</h4> <label ng-repeat="thing in dc.list"> <input type="checkbox" ng-checked="dc.individualSelections.indexOf(thing) > -1" ng-click="dc.addOrRemove(dc.individualSelections, thing, false)" > {{thing}} </label> <p> dc.invidualSelections :- {{dc.individualSelections}} </p> <script data-require="jquery@3.0.0" data-semver="3.0.0" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script> <script data-require="angular.js@1.5.6" data-semver="1.5.6" src="https://code.angularjs.org/1.5.6/angular.min.js"></script> <script src="script.js"></script> </body> </html>

其他回答

我喜欢Yoshi的回答。我增强了它,所以你可以对多个列表使用相同的函数。

<label ng-repeat="fruitName in fruits">
<input
type="checkbox"
name="selectedFruits[]"
value="{{fruitName}}"
ng-checked="selection.indexOf(fruitName) > -1"
ng-click="toggleSelection(fruitName, selection)"> {{fruitName}}
</label>


<label ng-repeat="veggieName in veggies">
<input
type="checkbox"
name="selectedVeggies[]"
value="{{veggieName}}"
ng-checked="veggieSelection.indexOf(veggieName) > -1"
ng-click="toggleSelection(veggieName, veggieSelection)"> {{veggieName}}
</label>



app.controller('SimpleArrayCtrl', ['$scope', function SimpleArrayCtrl($scope) {
  // fruits
  $scope.fruits = ['apple', 'orange', 'pear', 'naartjie'];
  $scope.veggies = ['lettuce', 'cabbage', 'tomato']
  // selected fruits
  $scope.selection = ['apple', 'pear'];
  $scope.veggieSelection = ['lettuce']
  // toggle selection for a given fruit by name
  $scope.toggleSelection = function toggleSelection(selectionName, listSelection) {
    var idx = listSelection.indexOf(selectionName);

    // is currently selected
    if (idx > -1) {
      listSelection.splice(idx, 1);
    }

    // is newly selected
    else {
      listSelection.push(selectionName);
    }
  };
}]);

http://plnkr.co/edit/KcbtzEyNMA8s1X7Hja8p?p=preview

有一种方法可以通过ng-model-options="{getterSetter: true}"直接处理数组并同时使用ng-model。

诀窍是在ng-model中使用getter/setter函数。通过这种方式,你可以使用一个数组作为你的真实模型,并“伪造”输入模型中的布尔值:

<label ng-repeat="fruitName in ['apple', 'orange', 'pear', 'naartjie']">
  <input
    type="checkbox"
    ng-model="fruitsGetterSetterGenerator(fruitName)"
    ng-model-options="{ getterSetter: true }"
  > {{fruitName}}
</label>

$scope.fruits = ['apple', 'pear']; // pre checked

$scope.fruitsGetterSetterGenerator = function(fruitName){
    return function myGetterSetter(nowHasFruit){
        if (nowHasFruit !== undefined){

            // Setter
            fruitIndex = $scope.fruits.indexOf(fruit);
            didHaveFruit = (fruitIndex !== -1);
            mustAdd = (!didHaveFruit && nowHasFruit);
            mustDel = (didHaveFruit && !nowHasFruit);
            if (mustAdd){
                $scope.fruits.push(fruit);
            }
            if (mustDel){
                $scope.fruits.splice(fruitIndex, 1);
            }
        }
        else {
            // Getter
            return $scope.user.fruits.indexOf(fruit) !== -1;
        }
    }
}

注意:如果你的数组很大,你不应该使用这个方法,因为myGetterSetter会被调用很多次。

要了解更多信息,请参见https://docs.angularjs.org/api/ng/directive/ngModelOptions。

我改编了Yoshi接受的答案来处理复杂的对象(而不是字符串)。

HTML

<div ng-controller="TestController">
    <p ng-repeat="permission in allPermissions">
        <input type="checkbox" ng-checked="selectedPermissions.containsObjectWithProperty('id', permission.id)" ng-click="toggleSelection(permission)" />
        {{permission.name}}
    </p>

    <hr />

    <p>allPermissions: | <span ng-repeat="permission in allPermissions">{{permission.name}} | </span></p>
    <p>selectedPermissions: | <span ng-repeat="permission in selectedPermissions">{{permission.name}} | </span></p>
</div>

JavaScript

Array.prototype.indexOfObjectWithProperty = function(propertyName, propertyValue)
{
    for (var i = 0, len = this.length; i < len; i++) {
        if (this[i][propertyName] === propertyValue) return i;
    }

    return -1;
};


Array.prototype.containsObjectWithProperty = function(propertyName, propertyValue)
{
    return this.indexOfObjectWithProperty(propertyName, propertyValue) != -1;
};


function TestController($scope)
{
    $scope.allPermissions = [
    { "id" : 1, "name" : "ROLE_USER" },
    { "id" : 2, "name" : "ROLE_ADMIN" },
    { "id" : 3, "name" : "ROLE_READ" },
    { "id" : 4, "name" : "ROLE_WRITE" } ];

    $scope.selectedPermissions = [
    { "id" : 1, "name" : "ROLE_USER" },
    { "id" : 3, "name" : "ROLE_READ" } ];

    $scope.toggleSelection = function toggleSelection(permission) {
        var index = $scope.selectedPermissions.indexOfObjectWithProperty('id', permission.id);

        if (index > -1) {
            $scope.selectedPermissions.splice(index, 1);
        } else {
            $scope.selectedPermissions.push(permission);
        }
    };
}

工作示例:http://jsfiddle.net/tCU8v/

这里还有另一个解决方案。我的解决方案的好处是:

它不需要任何额外的手表(这可能会影响性能) 它不需要控制器中的任何代码来保持干净 代码仍然有些短 它只需要很少的代码就可以在多个地方重用,因为它只是一个指令

下面是指令:

function ensureArray(o) {
    var lAngular = angular;
    if (lAngular.isArray(o) || o === null || lAngular.isUndefined(o)) {
        return o;
    }
    return [o];
}

function checkboxArraySetDirective() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attrs, ngModel) {
            var name = attrs.checkboxArraySet;

            ngModel.$formatters.push(function(value) {
                return (ensureArray(value) || []).indexOf(name) >= 0;
            });

            ngModel.$parsers.push(function(value) {
                var modelValue = ensureArray(ngModel.$modelValue) || [],
                    oldPos = modelValue.indexOf(name),
                    wasSet = oldPos >= 0;
                if (value) {
                    if (!wasSet) {
                        modelValue = angular.copy(modelValue);
                        modelValue.push(name);
                    }
                } else if (wasSet) {
                    modelValue = angular.copy(modelValue);
                    modelValue.splice(oldPos, 1);
                }
                return modelValue;
            });
        }
    }
}

最后就像这样使用它:

<input ng-repeat="fruit in ['apple', 'banana', '...']" type="checkbox" ng-model="fruits" checkbox-array-set="{{fruit}}" />

这就是全部了。唯一增加的是复选框-数组-set属性。

根据这个线程中的回答,我创建了涵盖所有情况的清单模型指令:

简单的原语数组 对象数组(选择id或整个对象) 对象属性迭代

对于主题启动案例,它将是:

<label ng-repeat="fruit in ['apple', 'orange', 'pear', 'naartjie']">
    <input type="checkbox" checklist-model="selectedFruits" checklist-value="fruit"> {{fruit}}
</label>