5

我正在使用 AngularJS v1.2.0-rc.3。

我有一个模型 y,与模型 x 有一对多的关系。

最初,我有一个模型 y 的表格,其中 xs 有多个选择,如下所示:

控制器:

function test($scope) {
  $scope.xs = [
    {id:1, value:'value 1'},
    {id:2, value:'value 2'},
    {id:3, value:'value 3'}
  ];
  $scope.y = {xs:[2]};
}

看法:

<div ng-controller="test">
  <select multiple ng-model="y.xs" ng-options="x.id as x.value for x in xs">
  </select>    
</div>

结果是所选项目的数组。

http://plnkr.co/edit/s3tvvHeyE17TVH5KNkPZ

一切都很好,但我需要将其更改为复选框列表,发现我不能再使用数组了。

我尝试使用中继器的索引,如下所示:

<div ng-repeat="x in xs">
  <input type="checkbox" ng-model="y.xs[$index]" ng-true-value="{{x.id}}"/>
  {{x.value}}
</div>

但是例如,要预先选择第二个项目,我需要使用它:

$scope.y = {xs: [null, '2']};

这是没用的。

http://plnkr.co/edit/9UfbKF2gFLnhTOKu3Yep

经过一番搜索,似乎推荐的方法是使用对象哈希,就像这样

<div ng-repeat="x in xs">
  <input type="checkbox" ng-model="y.xs[x.id]"/>
  {{x.value}}
</div>

http://plnkr.co/edit/Xek8alEJbwq3g0NAPMcF

但是如果取消选择项目,您最终会得到如下所示的内容:

y={
  "xs": {
    "1": false,
    "2": false,
    "3": false
  }
}

所以我最终添加了一个监视表达式来过滤掉错误值,如下所示:

$scope.$watch('y.xs', function(n) {
  for (var k in n) 
    if (n.hasOwnProperty(k) && !n[k]) 
      delete n[k];
}, true);

http://plnkr.co/edit/S1C1g5fYKzUZb7b0pRtp

它有效,但感觉不令人满意。

由于这是一个常见的用例,我很想知道其他人是如何解决它的。

更新

按照使用自定义指令的建议,我想出了这个解决方案,它将选择保持为一个列表。

指示:

angular.module('checkbox', [])
.directive('checkboxList', function () {
  return {
    restrict: 'A',
    replace: true,
    scope: {
      selection: '=',
      items: '=',
      value: '@',
      label: '@'
    },
    template: '<div ng-repeat="item in list">' +
      '<label>' +
      '<input type="checkbox" value="{{item.value}}" ng-checked="item.checked" ng-click="toggle($index)"/>' +
      '{{item.label}}' +
      '</label>' +
      '</div>',
    controller: ['$scope', function ($scope) {
      $scope.toggle = function (index) {
        var item = $scope.list[index],
          i = $scope.selection.indexOf(item.value);
        item.checked = !item.checked;
        if (!item.checked && i > -1) {
          $scope.selection.splice(i, 1);
        } else if (item.checked && i < 0) {
          $scope.selection.push(item.value);
        }
      };
      $scope.$watch('items', function (value) {
        $scope.list = [];
        if (angular.isArray(value)) {
          angular.forEach(value, function (item) {
            $scope.list.push({
              value: item[$scope.value],
              label: item[$scope.label],
              checked: $scope.selection.indexOf(item[$scope.value]) > -1
            });
          });
        }
      }, true);
    }]
  };
});

看法:

<div checkbox-list
     selection="a.bs"
     items="bs"
     value="id"
     label="name">
</div>

http://plnkr.co/edit/m7yH9bMPuRCg5OP2u0VX

4

3 回答 3

2

I had to write a multi select directive myself in the past, feel free to grab it at http://isteven.github.io/angular-multi-select.

As for the data binding approach, my data structure is actually quite similar with yours, but in my approach I added one more property which represent the checkbox state.

Example, with your input above, I added "checked":

$scope.xs = [
    { id:1, value:'value 1', checked: false },
    { id:2, value:'value 2', checked: false },
    { id:3, value:'value 3', checked: false }
];

And I pass it to the directive like this:

<div 
    multi-select 
    input-model="xs" 
    button-label="value" 
    item-label="id value" 
    tick-property="checked" >
</div>

When you tick / untick a checkbox, the directive will modify the input model $scope.xs.checked accordingly. To achieve this, i attach a click handler to each checkbox. This handler will call a function in which I pass the checkbox object as the function parameter. This function will then synchronize the checkbox state and the model.

To get the selected / ticked checkboxes, you will only need to loop $scope.xs over where .checked === true

Example:

angular.forEach( $scope.xs, function( value, key ) {
    if ( value.checked === true ) {
         // Do your stuff here
    }
});

Pardon my bad English, and hope this helps. Cheers.

于 2014-04-30T02:07:47.630 回答
1

我采用了指令方法。它给我留下了一个被检查对象的 ID 列表。这是一个小提琴JSFIDDLE。这就是我的 html 的样子。

<div ng-app="checkbox" ng-controller="homeCtrl">
    <div ng-repeat="item in list">
        <input type="checkbox" checkbox-group />
        <label>{{item.value}}</label>
    </div>{{array}}
    <br>{{update()}}
</div>

我的指令

.directive("checkboxGroup", function () {
    return {
        restrict: "A",
        link: function (scope, elem, attrs) {
            // Determine initial checked boxes
            if (scope.array.indexOf(scope.item.id) !== -1) {
                elem[0].checked = true;
            }

            // Update array on click
            elem.bind('click', function () {
                var index = scope.array.indexOf(scope.item.id);
                // Add if checked
                if (elem[0].checked) {
                    if (index === -1) scope.array.push(scope.item.id);
                }
                // Remove if unchecked
                else {
                    if (index !== -1) scope.array.splice(index, 1);
                }
                // Sort and update DOM display
                scope.$apply(scope.array.sort(function (a, b) {
                    return a - b
                }));
            });
        }
    }
});
于 2013-11-08T22:33:32.583 回答
0

我需要一个复选框解决方案,它还可以显示不在可能选择列表中的值(如果该列表在用户填写表单后发生了变化怎么办?)。

另外,我不认为手表功能是必要的。

最后,我需要传入表单,这样如果用户切换了任何复选框,我就可以将其设置为脏。

警告:在我的情况下,我只需要一个字符串数组作为我的模型,这并不是海报用于他的模型的确切内容。

HTML:

<multiple-checkbox
    form="form"
    selections="model"
    options="options">
</multiple-checkbox>

指示:

.directive("multipleCheckbox", function () {
    return {
        restrict: 'E',
        scope: {
            form: '=',
            selections: '=',
            options: '=',
        },
        template:
            '<div>' +
                '<div class="checkbox" ng-repeat="item in options">' +
                    '<label>' +
                        '<input type="checkbox" value="{{$index}}" ng-checked="selections.indexOf(item) > -1" ng-click="toggle(item)"/>' +
                        '{{item}}' +
                    '</label>' +
                '</div>' +
                '<div class="checkbox" ng-repeat="item in selections" ng-if="options.indexOf(item) === -1">' +
                    '<label>' +
                        '<input type="checkbox" value="{{options.length + $index}}" ng-checked="selections.indexOf(item) > -1" ng-click="toggle(item)"/>' +
                        '<strong>Other: </strong>{{item}}' +
                    '</label>' +
                '</div>' +
            '</div>',
        controller: ['$scope', function ($scope) {

            // Executed when the checkboxes are toggled
            $scope.toggle = function (item) {

                // set the form to dirty if we checked the boxes
                if ($scope.form) $scope.form.$dirty = true;

                // get the index of the selection
                var index = -1;
                if (angular.isArray($scope.selections)) {
                    index = $scope.selections.indexOf(item);
                }
                // if it's not already an array, initialize it
                else $scope.selections = [];

                if (index > -1) {
                    // remove the item
                    $scope.selections.splice(index, 1);
                    // if the array is empty, set it to null
                    if ($scope.selections.length === 0) {
                        $scope.selections = null;
                    }
                }
                else if (index < 0) {
                    // add the item
                    $scope.selections.push(item);
                }

            };
        }],
    };
});
于 2016-07-27T22:11:12.187 回答