How do I bind to list of checkbox values with AngularJS?

前端 未结 29 2310
天涯浪人
天涯浪人 2020-11-22 05:20

I have a few checkboxes:





        
相关标签:
29条回答
  • 2020-11-22 06:20

    In the HTML (supposing that the checkboxes are in the first column of every row in a table).

    <tr ng-repeat="item in fruits">
        <td><input type="checkbox" ng-model="item.checked" ng-click="getChecked(item)"></td>
        <td ng-bind="fruit.name"></td>
        <td ng-bind="fruit.color"></td>
        ...
    </tr>
    

    In the controllers.js file:

    // The data initialization part...
    $scope.fruits = [
        {
          name: ....,
          color:....
        },
        {
          name: ....,
          color:....
        }
         ...
        ];
    
    // The checked or not data is stored in the object array elements themselves
    $scope.fruits.forEach(function(item){
        item.checked = false;
    });
    
    // The array to store checked fruit items
    $scope.checkedItems = [];
    
    // Every click on any checkbox will trigger the filter to find checked items
    $scope.getChecked = function(item){
        $scope.checkedItems = $filter("filter")($scope.fruits,{checked:true});
    };
    
    0 讨论(0)
  • 2020-11-22 06:21

    I think the easiest workaround would be to use 'select' with 'multiple' specified:

    <select ng-model="selectedfruit" multiple ng-options="v for v in fruit"></select>
    

    Otherwise, I think you'll have to process the list to construct the list (by $watch()ing the model array bind with checkboxes).

    0 讨论(0)
  • 2020-11-22 06:21

    Based on my other post here, I have made a reusable directive.

    Check out the GitHub repository

    (function () {
       
       angular
          .module("checkbox-select", [])
          .directive("checkboxModel", ["$compile", function ($compile) {
             return {
                restrict: "A",
                link: function (scope, ele, attrs) {
                   // Defining updateSelection function on the parent scope
                   if (!scope.$parent.updateSelections) {
                      // 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.
                      scope.$parent.updateSelections = 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)
                            }
                         }
                      }   
                   }
                   
                   // Adding or removing attributes
                   ele.attr("ng-checked", attrs.checkboxModel + ".indexOf(" + attrs.checkboxValue + ") > -1")
                   var multiple = attrs.multiple ? "true" : "false"
                   ele.attr("ng-click", "updateSelections(" + [attrs.checkboxModel, attrs.checkboxValue, multiple].join(",") + ")")
                   
                   // Removing the checkbox-model attribute, 
                   // it will avoid recompiling the element infinitly
                   ele.removeAttr("checkbox-model")
                   ele.removeAttr("checkbox-value")
                   ele.removeAttr("multiple")
                   
                   $compile(ele)(scope)
                }
             }
          }])
       
          // Defining app and controller
          angular
          .module("APP", ["checkbox-select"])
          .controller("demoCtrl", ["$scope", function ($scope) {
             var dc = this
             dc.list = [
                "selection1",
                "selection2",
                "selection3"
             ]
             
             // Define the selections containers here
             dc.multipleSelections = []
             dc.individualSelections = []
          }])
       
    })()
    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" checkbox-model="dc.multipleSelections" checkbox-value="thing" multiple>
             {{thing}}
          </label>
          <p>dc.multipleSelecitons:- {{dc.multipleSelections}}</p>
          
          <h4>Individual Selections</h4>
          <label ng-repeat="thing in dc.list">
             <input type="checkbox" checkbox-model="dc.individualSelections" checkbox-value="thing">
             {{thing}}
          </label>
          <p>dc.individualSelecitons:- {{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>

    0 讨论(0)
  • 2020-11-22 06:24

    Since you accepted an answer in which a list was not used, I'll assume the answer to my comment question is "No, it doesn't have to be a list". I also had the impression that maybe you were rending the HTML server side, since "checked" is present in your sample HTML (this would not be needed if ng-model were used to model your checkboxes).

    Anyway, here's what I had in mind when I asked the question, also assuming you were generating the HTML server-side:

    <div ng-controller="MyCtrl" 
     ng-init="checkboxes = {apple: true, orange: false, pear: true, naartjie: false}">
        <input type="checkbox" ng-model="checkboxes.apple">apple
        <input type="checkbox" ng-model="checkboxes.orange">orange
        <input type="checkbox" ng-model="checkboxes.pear">pear
        <input type="checkbox" ng-model="checkboxes.naartjie">naartjie
        <br>{{checkboxes}}
    </div>
    

    ng-init allows server-side generated HTML to initially set certain checkboxes.

    Fiddle.

    0 讨论(0)
  • 2020-11-22 06:26

    There is a way to work on the array directly and use ng-model at the same time through ng-model-options="{ getterSetter: true }".

    The trick is to use a getter/setter function in your ng-model. This way you can use an array as your real model and "fake" the booleans in the input's model:

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

    CAVEAT You shouldn't use this method if your arrays are big as myGetterSetter will be called a lot of times.

    For more on that, see https://docs.angularjs.org/api/ng/directive/ngModelOptions.

    0 讨论(0)
提交回复
热议问题