Как связать со списком значений флажков с AngularJS?

670

У меня есть несколько флажков:

<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-модель может привязать значение только одного флажка к переменной в контроллере.

Есть ли другой способ сделать это, чтобы я мог привязать четыре флажка к списку в контроллере?

nickponline
источник
23
Это должен быть список? Будет ли объект работать ?: <input type='checkbox' ng-model="checkboxes.apple">и т. Д. Модель будет выглядеть следующим образом: {"apple": true, "orange": false, "pear": true, "naartjie": true}
Марк Райкок
2
Попробуйте директиву в этом репо
Викас Гаутам
1
Обязательно посмотрите мимо принятого ответа. Есть другой ответ, который, на мой взгляд, гораздо более элегантный.
Джейсон Светт
3
naartjie!? Это просто дает тебе бот! : D
Петр Кула
1
@ppumkin хе-хе только что видел это Вы правы: D
nickponline

Ответы:

927

Есть два способа решения этой проблемы. Либо используйте простой массив или массив объектов. У каждого решения есть свои плюсы и минусы. Ниже вы найдете один для каждого случая.


С простым массивом в качестве входных данных

HTML может выглядеть так:

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

И соответствующий код контроллера будет:

app.controller('SimpleArrayCtrl', ['$scope', function SimpleArrayCtrl($scope) {

  // Fruits
  $scope.fruits = ['apple', 'orange', 'pear', 'naartjie'];

  // Selected fruits
  $scope.selection = ['apple', 'pear'];

  // Toggle selection for a given fruit by name
  $scope.toggleSelection = function toggleSelection(fruitName) {
    var idx = $scope.selection.indexOf(fruitName);

    // Is currently selected
    if (idx > -1) {
      $scope.selection.splice(idx, 1);
    }

    // Is newly selected
    else {
      $scope.selection.push(fruitName);
    }
  };
}]);

Плюсы : простая структура данных и переключение по имени просты в обращении

Минусы : Добавить / удалить обременительно, так как необходимо управлять двумя списками (ввод и выбор)


С массивом объектов в качестве входных данных

HTML может выглядеть так:

<label ng-repeat="fruit in fruits">
  <!--
    - Use `value="{{fruit.name}}"` to give the input a real value, in case the form gets submitted
      traditionally

    - Use `ng-checked="fruit.selected"` to have the checkbox checked based on some angular expression
      (no two-way-data-binding)

    - Use `ng-model="fruit.selected"` to utilize two-way-data-binding. Note that `.selected`
      is arbitrary. The property name could be anything and will be created on the object if not present.
  -->
  <input
    type="checkbox"
    name="selectedFruits[]"
    value="{{fruit.name}}"
    ng-model="fruit.selected"
  > {{fruit.name}}
</label>

И соответствующий код контроллера будет:

app.controller('ObjectArrayCtrl', ['$scope', 'filterFilter', function ObjectArrayCtrl($scope, filterFilter) {

  // Fruits
  $scope.fruits = [
    { name: 'apple',    selected: true },
    { name: 'orange',   selected: false },
    { name: 'pear',     selected: true },
    { name: 'naartjie', selected: false }
  ];

  // Selected fruits
  $scope.selection = [];

  // Helper method to get selected fruits
  $scope.selectedFruits = function selectedFruits() {
    return filterFilter($scope.fruits, { selected: true });
  };

  // Watch fruits for changes
  $scope.$watch('fruits|filter:{selected:true}', function (nv) {
    $scope.selection = nv.map(function (fruit) {
      return fruit.name;
    });
  }, true);
}]);

Плюсы : добавить / удалить очень легко

Минусы : несколько более сложная структура данных и переключение по имени громоздки или требуют вспомогательного метода


Демо : http://jsbin.com/ImAqUC/1/

Йоши
источник
10
К вашему сведению, вместо внедрения $ filter вы можете ввести filterFilter, а затем использовать его следующим образом: return filterFilter ($ scope.fruits, {checked: true}); Встроенный и пользовательский фильтры зарегистрированы в $ инжекторе с именем filterNameFilter («filterName» должно быть выделено курсивом) - Документы $ filterProvider
Марк Райкок
24
value="{{fruit.name}}"и ng-checked="fruit.checked"излишни, так как используется ng-модель.
Марк Райкок
3
Я заметил, что нет необходимости указывать «проверено» в модели, Angular установит свойство автоматически :)
daveoncode
3
Следует использовать ng-change вместо ng-click, поскольку он лучше справляется с крайними случаями.
amccausl
2
@ViktorMolokostov Это было бы полезно, если бы вы отправили форму традиционно . Это означает отправку его в обработчик действий (некоторый серверный скрипт). С php элемент формы с таким именем (используя квадратные скобки) создает массив в данных запроса. Таким образом, вы можете легко обрабатывать выбранные фрукты.
Йоши
406

Простое решение:

<div ng-controller="MainCtrl">
  <label ng-repeat="(color,enabled) in colors">
      <input type="checkbox" ng-model="colors[color]" /> {{color}} 
  </label>
  <p>colors: {{colors}}</p>
</div>

<script>
  var app = angular.module('plunker', []);

  app.controller('MainCtrl', function($scope){
      $scope.colors = {Blue: true, Orange: true};
  });
</script>

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

kolypto
источник
57
@kolypto - это определенно ответ. Я переписал это для людей (таких как я), которые работают с объектами: plnkr.co/edit/cqsADe8lKegsBMgWMyB8?p=preview
Kyle
5
Я делаю это так же, как вы, но что делает включенный в (color,enabled) in colors?
Себастьян
3
@Sebastian, так colorsкак это объект, когда вы повторяете его - вы получаете пары (key,value).
Колыпто
10
Хотя мне очень нравится этот ответ! Я думаю, что есть одна большая проблема с использованием объектов в качестве источника данных. То есть, поскольку по определению порядок свойств объектов не определен, при отображении флажков нельзя указать определенный порядок. Еще +1;)
Йоши
2
colorsНадо называть isSelected, это гораздо легче читать, isSelected[color]чемcolors[color]
Дмитрий Зайцев
87
<input type='checkbox' ng-repeat="fruit in fruits"
  ng-checked="checkedFruits.indexOf(fruit) != -1" ng-click="toggleCheck(fruit)">

,

function SomeCtrl ($scope) {
    $scope.fruits = ["apple, orange, pear, naartjie"];
    $scope.checkedFruits = [];
    $scope.toggleCheck = function (fruit) {
        if ($scope.checkedFruits.indexOf(fruit) === -1) {
            $scope.checkedFruits.push(fruit);
        } else {
            $scope.checkedFruits.splice($scope.checkedFruits.indexOf(fruit), 1);
        }
    };
}
Умур Контачи
источник
2
Мне нравится, насколько это просто, именно то, что я ищу (хотя я должен признать, что директива @vitalets удивительна). Я немного изменил код Умура, чтобы создать эту скрипку: jsfiddle.net/samurai_jane/9mwsbfuc
samurai_jane
Я делаю слова Самурай Джейн мои! Как просто было показать, что мне нужно! :)
Фрэнсис Родригес
81

Вот небольшая директива многократного использования, которая, кажется, делает то, что вы ищете. Я просто назвал это checkList. Он обновляет массив при изменении флажков и обновляет флажки при изменении массива.

app.directive('checkList', function() {
  return {
    scope: {
      list: '=checkList',
      value: '@'
    },
    link: function(scope, elem, attrs) {
      var handler = function(setup) {
        var checked = elem.prop('checked');
        var index = scope.list.indexOf(scope.value);

        if (checked && index == -1) {
          if (setup) elem.prop('checked', false);
          else scope.list.push(scope.value);
        } else if (!checked && index != -1) {
          if (setup) elem.prop('checked', true);
          else scope.list.splice(index, 1);
        }
      };

      var setupHandler = handler.bind(null, true);
      var changeHandler = handler.bind(null, false);

      elem.bind('change', function() {
        scope.$apply(changeHandler);
      });
      scope.$watch('list', setupHandler, true);
    }
  };
});

Вот контроллер и представление, которое показывает, как вы можете использовать его.

<div ng-app="myApp" ng-controller='MainController'>
  <span ng-repeat="fruit in fruits">
    <input type='checkbox' value="{{fruit}}" check-list='checked_fruits'> {{fruit}}<br />
  </span>

  <div>The following fruits are checked: {{checked_fruits | json}}</div>

  <div>Add fruit to the array manually:
    <button ng-repeat="fruit in fruits" ng-click='addFruit(fruit)'>{{fruit}}</button>
  </div>
</div>
app.controller('MainController', function($scope) {
  $scope.fruits = ['apple', 'orange', 'pear', 'naartjie'];
  $scope.checked_fruits = ['apple', 'pear'];
  $scope.addFruit = function(fruit) {
    if ($scope.checked_fruits.indexOf(fruit) != -1) return;
    $scope.checked_fruits.push(fruit);
  };
});

(Кнопки демонстрируют, что изменение массива также обновит флажки.)

Наконец, вот пример действующей директивы по Плункеру: http://plnkr.co/edit/3YNLsyoG4PIBW6Kj7dRK?p=preview

Мишель Тилли
источник
2
Спасибо Брэндону, это сделало именно то, что я хотел (и именно то, о чем спрашивал вопрос, в отличие от других ответов). Единственная настройка, которую я сделал, состояла в том, чтобы заменить ваш "elem.on ('change', function () ..." на "elem.bind ('change', function () ..."), чтобы удалить зависимость от jQuery .
Jonathan Моффат
Это довольно аккуратно, но как-то разрушает мою способность использовать ng-disabled :( Есть ли способ, которым я могу это исправить?
Николай Дам Ларсен
Супер полезно! И даже работал для меня с объектами вместо массивов как для списка источников, так и для списка данных!
SteveShaffer
Я согласен со всеми. Это самый полезный и, несомненно, многоразовый! Спасибо за хорошую работу. :)
maksbd19
2
Если у вас есть проблемы с AngularJS> = 1.4.4, проверьте github.com/angular/angular.js/issues/13037 : замените value: '@'наvalue: '=ngValue'
tanguy_k
66

На основе ответов в этой теме я создал директиву checklist-model, которая охватывает все случаи:

  • простой массив примитивов
  • массив объектов (выбрать идентификатор или весь объект)
  • итерация свойств объекта

Для тематического начального случая это будет:

<label ng-repeat="fruit in ['apple', 'orange', 'pear', 'naartjie']">
    <input type="checkbox" checklist-model="selectedFruits" checklist-value="fruit"> {{fruit}}
</label>
vitalets
источник
Это выглядит как то, что мне нужно. Есть ли шанс, что вы сможете объяснить, как использовать его при асинхронном получении данных? Эта часть смущает меня.
Дэн Канкро
После асинхронного получения данных просто измените модель checlist в области видимости, в приведенном выше примере selectedFruits.
Адриан Бер
11

Использование строки $indexможет помочь использовать хэш-карту выбранных значений:

<ul>
    <li ng-repeat="someItem in someArray">
        <input type="checkbox" ng-model="someObject[$index.toString()]" />
    </li>
</ul>

Таким образом, объект ng-модели обновляется ключом, представляющим индекс.

$scope.someObject = {};

Через некоторое время $scope.someObjectдолжно выглядеть примерно так:

$scope.someObject = {
     0: true,
     4: false,
     1: true
};

Этот метод не подходит для всех ситуаций, но его легко реализовать.

user2479438
источник
Это очень элегантное решение и подходит для моего случая (с использованием AJAX)
Стефан Райер
использует метод поцелуя
Geomorillo
8

Поскольку вы приняли ответ, в котором список не использовался, я предполагаю, что ответ на мой вопрос-комментарий «Нет, это не обязательно должен быть список». У меня также создалось впечатление, что, возможно, вы обновляете серверную часть HTML, поскольку в вашем примере HTML присутствует «флажок» (в этом не было бы необходимости, если бы ng-model использовался для моделирования ваших флажков).

В любом случае, вот что я имел в виду, когда задавал вопрос, также предполагая, что вы генерируете серверную часть HTML:

<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 позволяет сгенерированному на стороне сервера HTML изначально устанавливать определенные флажки.

Скрипки .

Марк Райкок
источник
8

Я думаю, что самый простой обходной путь - это использовать «select» с указанием «множественного»:

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

В противном случае, я думаю, вам придется обработать список, чтобы построить список (с $watch()помощью привязки массива модели с флажками).

вздор
источник
3
Он просит список флажков, и все же вы говорите ему о выборе с опциями. Который совершенно другой.
CrazySabbath
@CrazySabbath: пока вы не понимаете, что он предложил альтернативное решение, и этот ответ помог 6 другим людям в качестве «альтернативного решения»
curiousBoy
5

Я адаптировал принятый ответ Йоши, чтобы иметь дело со сложными объектами (вместо строк).

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/

Адам
источник
1
Вы никогда не должны иметь <input type="checkbox">без упаковки или соответствия <label>! Теперь ваши пользователи должны нажимать на фактический флажок вместо текста рядом с флажком, что намного сложнее и плохо подходит для использования.
Скотт
5

Другая простая директива может быть такой:

var appModule = angular.module("appModule", []);

appModule.directive("checkList", [function () {
return {
    restrict: "A",
    scope: {
        selectedItemsArray: "=",
        value: "@"
    },
    link: function (scope, elem) {
        scope.$watchCollection("selectedItemsArray", function (newValue) {
            if (_.contains(newValue, scope.value)) {
                elem.prop("checked", true);
            } else {
                elem.prop("checked", false);
            }
        });
        if (_.contains(scope.selectedItemsArray, scope.value)) {
            elem.prop("checked", true);
        }
        elem.on("change", function () {
            if (elem.prop("checked")) {
                if (!_.contains(scope.selectedItemsArray, scope.value)) {
                    scope.$apply(
                        function () {
                            scope.selectedItemsArray.push(scope.value);
                        }
                    );
                }
            } else {
                if (_.contains(scope.selectedItemsArray, scope.value)) {
                    var index = scope.selectedItemsArray.indexOf(scope.value);
                    scope.$apply(
                        function () {
                            scope.selectedItemsArray.splice(index, 1);
                        });
                }
            }
            console.log(scope.selectedItemsArray);
        });
    }
};
}]);

Контроллер:

appModule.controller("sampleController", ["$scope",
  function ($scope) {
    //#region "Scope Members"
    $scope.sourceArray = [{ id: 1, text: "val1" }, { id: 2, text: "val2" }];
    $scope.selectedItems = ["1"];
    //#endregion
    $scope.selectAll = function () {
      $scope.selectedItems = ["1", "2"];
  };
    $scope.unCheckAll = function () {
      $scope.selectedItems = [];
    };
}]);

И HTML:

<ul class="list-unstyled filter-list">
<li data-ng-repeat="item in sourceArray">
    <div class="checkbox">
        <label>
            <input type="checkbox" check-list selected-items-array="selectedItems" value="{{item.id}}">
            {{item.text}}
        </label>
    </div>
</li>

Я также включаю Плункер: http://plnkr.co/edit/XnFtyij4ed6RyFwnFN6V?p=preview

Адриан Станеску
источник
5

Следующее решение кажется хорошим вариантом,

<label ng-repeat="fruit in fruits">
  <input
    type="checkbox"
    ng-model="fruit.checked"
    ng-value="true"
  > {{fruit.fruitName}}
</label>

И в модели контроллера значение fruitsбудет таким

$scope.fruits = [
  {
    "name": "apple",
    "checked": true
  },
  {
    "name": "orange"
  },
  {
    "name": "grapes",
    "checked": true
  }
];
Мохаммед Сейфер
источник
чем больше я смотрю на эти примеры, тем больше мне кажется, что мне придется отображать свой массив в массив объектов.
Winnemucca
4

Вам не нужно писать весь этот код. AngularJS будет поддерживать синхронизацию модели и флажков, просто используя ngTrueValue и ngFalseValue

Codepen здесь: http://codepen.io/paulbhartzog/pen/kBhzn

Фрагмент кода:

<p ng-repeat="item in list1" class="item" id="{{item.id}}">
  <strong>{{item.id}}</strong> <input name='obj1_data' type="checkbox" ng-model="list1[$index].data" ng-true-value="1" ng-false-value="0"> Click this to change data value below
</p>
<pre>{{list1 | json}}</pre>
Пол Б. Харцог
источник
Это не то, что требует OP.
bfontaine
Привязка флажков к списку - вот что спросили, и что я сделал. Массив можно изменить в соответствии с приложением. Дело в том, что флажки связаны. ngTrueValue и ngFalseValue также можно использовать для сопоставления со вторым массивом, в котором перечислены только другие атрибуты, например имена.
Пол Б. Харцог,
OP хочет список проверенных значений, а не список всех значений, проверенных и непроверенных.
bfontaine
4

Проверьте эту директиву, которая эффективно управляет списками флажков. Я надеюсь, что это работает для вас. Модель CheckList

DSB
источник
4

Есть способ работать с массивом напрямую и одновременно использовать ng-модель ng-model-options="{ getterSetter: true }".

Хитрость заключается в том, чтобы использовать функцию получения / установки в вашей ng-модели. Таким образом, вы можете использовать массив в качестве реальной модели и «подделать» логические значения в модели входа:

<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 Вы не должны использовать этот метод, если ваши массивы большие, как myGetterSetterбудет вызываться много раз.

Подробнее об этом см. Https://docs.angularjs.org/api/ng/directive/ngModelOptions .

Дэвид
источник
3

Мне нравится ответ Йоши. Я улучшил его, чтобы вы могли использовать одну и ту же функцию для нескольких списков.

<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

Bikey
источник
3

Если у вас есть несколько флажков в одной форме

Код контроллера

vm.doYouHaveCheckBox = ['aaa', 'ccc', 'bbb'];
vm.desiredRoutesCheckBox = ['ddd', 'ccc', 'Default'];
vm.doYouHaveCBSelection = [];
vm.desiredRoutesCBSelection = [];

Посмотреть код

<div ng-repeat="doYouHaveOption in vm.doYouHaveCheckBox">
    <div class="action-checkbox">
        <input id="{{doYouHaveOption}}" type="checkbox" value="{{doYouHaveOption}}" ng-checked="vm.doYouHaveCBSelection.indexOf(doYouHaveOption) > -1" ng-click="vm.toggleSelection(doYouHaveOption,vm.doYouHaveCBSelection)" />
        <label for="{{doYouHaveOption}}"></label>
        {{doYouHaveOption}}
    </div>
</div>

<div ng-repeat="desiredRoutesOption in vm.desiredRoutesCheckBox">
     <div class="action-checkbox">
          <input id="{{desiredRoutesOption}}" type="checkbox" value="{{desiredRoutesOption}}" ng-checked="vm.desiredRoutesCBSelection.indexOf(desiredRoutesOption) > -1" ng-click="vm.toggleSelection(desiredRoutesOption,vm.desiredRoutesCBSelection)" />
          <label for="{{desiredRoutesOption}}"></label>
          {{desiredRoutesOption}}
     </div>
</div>        
Рама Кришна Ила
источник
3

Вдохновленный постом Йоши выше. Вот плнкр .

(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>

Викас Гаутам
источник
3

Основано на моем другом посте здесь , я сделал директиву многократного использования.

Проверьте репозиторий GitHub

(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>

Викас Гаутам
источник
3

В HTML (предположим, что флажки находятся в первом столбце каждой строки таблицы).

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

В controllers.jsфайле:

// 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});
};
lqt0223
источник
3

Вот еще одно решение. Преимущество моего решения:

  • Для этого не нужны никакие дополнительные часы (что может повлиять на производительность)
  • Это не требует никакого кода в контроллере, поддерживающем его в чистоте
  • Код все еще несколько короткий
  • Требуется очень мало кода для повторного использования в нескольких местах, потому что это просто директива

Вот директива:

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

И это все, что есть. Единственным дополнением является checkbox-array-setатрибут.

янки
источник
3

Вы можете комбинировать AngularJS и jQuery. Например, вам нужно определить массив $scope.selected = [];в контроллере.

<label ng-repeat="item in items">
    <input type="checkbox" ng-model="selected[$index]" ng-true-value="'{{item}}'">{{item}}
</label>

Вы можете получить массив, владеющий выбранными элементами. Используя метод alert(JSON.stringify($scope.selected)), вы можете проверить выбранные элементы.

Dahai
источник
Отлично! ... это самое простое решение с использованием массива, а не объекта
Mario Campa
3
Не объединяйте Jquery и Angular
Йенс Алениус
Это приведет к дырам в выбранном массиве. Проверьте это сообщение
Викас Гаутам
2
  <div ng-app='app' >
    <div ng-controller='MainCtrl' >
       <ul> 
       <li ng-repeat="tab in data">
         <input type='checkbox' ng-click='change($index,confirm)' ng-model='confirm' />
         {{tab.name}} 
         </li>
     </ul>
    {{val}}
   </div>
 </div>


var app = angular.module('app', []);
 app.controller('MainCtrl',function($scope){
 $scope.val=[];
  $scope.confirm=false;
  $scope.data=[
   {
     name:'vijay'
     },
    {
      name:'krishna'
    },{
      name:'Nikhil'
     }
    ];
    $scope.temp;
   $scope.change=function(index,confirm){
     console.log(confirm);
    if(!confirm){
     ($scope.val).push($scope.data[index]);   
    }
    else{
    $scope.temp=$scope.data[index];
        var d=($scope.val).indexOf($scope.temp);
        if(d!=undefined){
         ($scope.val).splice(d,1);
        }    
       }
     }   
   })
vijay007
источник
1

Посмотрите это: контрольный список-модель .

Он работает с массивами JavaScript и объектами и может использовать статические флажки HTML без ng-repeat

<label><input type="checkbox" checklist-model="roles" value="admin"> Administrator</label>
<label><input type="checkbox" checklist-model="roles" value="customer"> Customer</label>
<label><input type="checkbox" checklist-model="roles" value="guest"> Guest</label>
<label><input type="checkbox" checklist-model="roles" value="user"> User</label>

И сторона JavaScript:

var app = angular.module("app", ["checklist-model"]);
app.controller('Ctrl4a', function($scope) {
    $scope.roles = [];
});
sarkiroka
источник
1

Простой HTML единственный способ сделать это:

<input type="checkbox"
       ng-checked="fruits.indexOf('apple') > -1"
       ng-click="fruits.indexOf('apple') > -1 ? fruits.splice(fruits.indexOf('apple'), 1) : fruits.push('apple')">
<input type="checkbox"
       ng-checked="fruits.indexOf('orange') > -1"
       ng-click="fruits.indexOf('orange') > -1 ? fruits.splice(fruits.indexOf('orange'), 1) : fruits.push('orange')">
<input type="checkbox"
       ng-checked="fruits.indexOf('pear') > -1"
       ng-click="fruits.indexOf('pear') > -1 ? fruits.splice(fruits.indexOf('pear'), 1) : fruits.push('pear')">
<input type="checkbox"
       ng-checked="fruits.indexOf('naartjie') > -1"
       ng-click="fruits.indexOf('apple') > -1 ? fruits.splice(fruits.indexOf('apple'), 1) : fruits.push('naartjie')">

Мэтт Кэрролл
источник
1

Используя этот пример @Umur Kontacı, я думаю использовать с помощью перехвата выбранных данных в другом объекте / массиве, например, на странице редактирования.

Варианты ловли в базе данных

введите описание изображения здесь

Переключить некоторые опции

введите описание изображения здесь

Как пример, все цвета JSON приведены ниже:

{
    "colors": [
        {
            "id": 1,
            "title": "Preto - #000000"
        },
        {
            "id": 2,
            "title": "Azul - #005AB1"
        },
        {
            "id": 3,
            "title": "Azul Marinho - #001A66"
        },
        {
            "id": 4,
            "title": "Amarelo - #FFF100"
        },
        {
            "id": 5,
            "title": "Vermelho - #E92717"
        },
        {
            "id": 6,
            "title": "Verde - #008D2F"
        },
        {
            "id": 7,
            "title": "Cinza - #8A8A8A"
        },
        {
            "id": 8,
            "title": "Prata - #C8C9CF"
        },
        {
            "id": 9,
            "title": "Rosa - #EF586B"
        },
        {
            "id": 10,
            "title": "Nude - #E4CAA6"
        },
        {
            "id": 11,
            "title": "Laranja - #F68700"
        },
        {
            "id": 12,
            "title": "Branco - #FFFFFF"
        },
        {
            "id": 13,
            "title": "Marrom - #764715"
        },
        {
            "id": 14,
            "title": "Dourado - #D9A300"
        },
        {
            "id": 15,
            "title": "Bordo - #57001B"
        },
        {
            "id": 16,
            "title": "Roxo - #3A0858"
        },
        {
            "id": 18,
            "title": "Estampado "
        },
        {
            "id": 17,
            "title": "Bege - #E5CC9D"
        }
    ]
}

И 2 типа объекта данных, arrayс одним объектом и objectсодержащие два / более объекта данных:

  • Два выбранных предмета попали в базу данных:

    [{"id":12,"title":"Branco - #FFFFFF"},{"id":16,"title":"Roxo - #3A0858"}]
  • Один выбранный элемент попал в базу данных:

    {"id":12,"title":"Branco - #FFFFFF"}

И вот мой код JavaScript:

/**
 * Add this code after catch data of database.
 */

vm.checkedColors = [];
var _colorObj = vm.formData.color_ids;
var _color_ids = [];

if (angular.isObject(_colorObj)) {
    // vm.checkedColors.push(_colorObj);
    _color_ids.push(_colorObj);
} else if (angular.isArray(_colorObj)) {
    angular.forEach(_colorObj, function (value, key) {
        // vm.checkedColors.push(key + ':' + value);
        _color_ids.push(key + ':' + value);
    });
}

angular.forEach(vm.productColors, function (object) {
    angular.forEach(_color_ids, function (color) {
        if (color.id === object.id) {
            vm.checkedColors.push(object);
        }
    });
});

/**
 * Add this code in your js function initialized in this HTML page
 */
vm.toggleColor = function (color) {
    console.log('toggleColor is: ', color);

    if (vm.checkedColors.indexOf(color) === -1) {
        vm.checkedColors.push(color);
    } else {
        vm.checkedColors.splice(vm.checkedColors.indexOf(color), 1);
    }
    vm.formData.color_ids = vm.checkedColors;
};

Мой HTML-код:

<div class="checkbox" ng-repeat="color in productColors">
    <label>
        <input type="checkbox"
               ng-checked="checkedColors.indexOf(color) != -1"
               ng-click="toggleColor(color)"/>
        <% color.title %>
    </label>
</div>

<p>checkedColors Output:</p>
<pre><% checkedColors %></pre>

[Изменить] Рефакторинг кода ниже:

function makeCheckedOptions(objectOptions, optionObj) {
    var checkedOptions = [];
    var savedOptions = [];

    if (angular.isObject(optionObj)) {
        savedOptions.push(optionObj);
    } else if (angular.isArray(optionObj)) {
        angular.forEach(optionObj, function (value, key) {
            savedOptions.push(key + ':' + value);
        });
    }

    angular.forEach(objectOptions, function (object) {
        angular.forEach(savedOptions, function (color) {
            if (color.id === object.id) {
                checkedOptions.push(object);
            }
        });
    });

    return checkedOptions;
}

И вызвать новый метод, как показано ниже:

vm.checkedColors = makeCheckedOptions(productColors, vm.formData.color_ids);

Это оно!

Фрэнсис Родригес
источник
1

Я положил массив в контроллере.

$scope.statuses = [{ name: 'Shutdown - Reassessment Required' },
    { name: 'Under Construction' },
    { name: 'Administrative Cancellation' },
    { name: 'Initial' },
    { name: 'Shutdown - Temporary' },
    { name: 'Decommissioned' },
    { name: 'Active' },
    { name: 'SO Shutdown' }]

На разметке я поставил что-то вроде следующего

<div ng-repeat="status in $scope.statuses">
   <input type="checkbox" name="unit_status" ng-model="$scope.checkboxes[status.name]"> {{status.name}}
   <br>                        
</div>
{{$scope.checkboxes}}

Вывод был следующий, в контроллере мне просто нужно было проверить, является ли он истинным или ложным; true для проверенного, отсутствует / false для непроверенного.

{
"Administrative Cancellation":true,
"Under Construction":true,
"Shutdown - Reassessment Required":true,
"Decommissioned":true,
"Active":true
}

Надеюсь это поможет.

Mahib
источник
0

Я думаю, что следующий способ более понятен и полезен для вложенных ng-повторов. Проверьте это на Plunker .

Цитата из этой темы :

<html ng-app="plunker">
    <head>
        <title>Test</title>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.4/angular.min.js"></script>
    </head>

    <body ng-controller="MainCtrl">
        <div ng-repeat="tab in mytabs">

            <h1>{{tab.name}}</h1>
            <div ng-repeat="val in tab.values">
                <input type="checkbox" ng-change="checkValues()" ng-model="val.checked"/>
            </div>
        </div>

        <br>
        <pre> {{selected}} </pre>

            <script>
                var app = angular.module('plunker', []);

                app.controller('MainCtrl', function ($scope,$filter) {
                    $scope.mytabs = [
             {
                 name: "tab1",
                 values: [
                     { value: "value1",checked:false },
                     { value: "value2", checked: false },
                     { value: "value3", checked: false },
                     { value: "value4", checked: false }
                 ]
             },
             {
                 name: "tab2",
                 values: [
                     { value: "value1", checked: false },
                     { value: "value2", checked: false },
                     { value: "value3", checked: false },
                     { value: "value4", checked: false }
                 ]
             }
                    ]
                    $scope.selected = []
                    $scope.checkValues = function () {
                        angular.forEach($scope.mytabs, function (value, index) {
                         var selectedItems = $filter('filter')(value.values, { checked: true });
                         angular.forEach(selectedItems, function (value, index) {
                             $scope.selected.push(value);
                         });

                        });
                    console.log($scope.selected);
                    };
                });
        </script>
    </body>
</html>
Oğuz Can Sertel
источник
0

Вот ссылка на jsFillde для того же, http://jsfiddle.net/techno2mahi/Lfw96ja6/ .

При этом используется директива, которая доступна для скачивания по адресу http://vitalets.github.io/checklist-model/ .

Это хорошо иметь директиву, так как ваше приложение будет нуждаться в этой функции очень часто.

Код ниже:

HTML:

<div class="container">
    <div class="ng-scope" ng-app="app" ng-controller="Ctrl1">
        <div class="col-xs-12 col-sm-6">
            <h3>Multi Checkbox List Demo</h3>
            <div class="well">  <!-- ngRepeat: role in roles -->
                <label ng-repeat="role in roles">
                    <input type="checkbox" checklist-model="user.roles" checklist-value="role"> {{role}}
                </label>
            </div>

            <br>
            <button ng-click="checkAll()">check all</button>
            <button ng-click="uncheckAll()">uncheck all</button>
            <button ng-click="checkFirst()">check first</button>
            <div>
                <h3>Selected User Roles </h3>
                <pre class="ng-binding">{{user.roles|json}}</pre>
            </div>

            <br>
            <div><b/>Provided by techno2Mahi</b></div>
        </div>

JavaScript

var app = angular.module("app", ["checklist-model"]);
app.controller('Ctrl1', function($scope) {
  $scope.roles = [
    'guest',
    'user',
    'customer',
    'admin'
  ];
  $scope.user = {
    roles: ['user']
  };
  $scope.checkAll = function() {
    $scope.user.roles = angular.copy($scope.roles);
  };
  $scope.uncheckAll = function() {
    $scope.user.roles = [];
  };
  $scope.checkFirst = function() {
    $scope.user.roles.splice(0, $scope.user.roles.length);
    $scope.user.roles.push('guest');
  };
});
Мээндра
источник
HTML не правильно сформирован - открывающих тегов <div>больше, чем закрывающих </div>. Вы что-то оставили?
Питер Мортенсен
0

Попробуйте моего ребенка:

**

myApp.filter('inputSelected', function(){
  return function(formData){
    var keyArr = [];
    var word = [];
    Object.keys(formData).forEach(function(key){
    if (formData[key]){
        var keyCap = key.charAt(0).toUpperCase() + key.slice(1);
      for (var char = 0; char<keyCap.length; char++ ) {
        if (keyCap[char] == keyCap[char].toUpperCase()){
          var spacedLetter = ' '+ keyCap[char];
          word.push(spacedLetter);
        }
        else {
          word.push(keyCap[char]);
        }
      }
    }
    keyArr.push(word.join(''))
    word = [];
    })
    return keyArr.toString();
  }
})

**

Затем для любой ng-модели с флажками она вернет строку всех выбранных вами входных данных:

<label for="Heard about ITN">How did you hear about ITN?: *</label><br>
<label class="checkbox-inline"><input ng-model="formData.heardAboutItn.brotherOrSister" type="checkbox" >Brother or Sister</label>
<label class="checkbox-inline"><input ng-model="formData.heardAboutItn.friendOrAcquaintance" type="checkbox" >Friend or Acquaintance</label>


{{formData.heardAboutItn | inputSelected }}

//returns Brother or Sister, Friend or Acquaintance
Саманта Гергененова
источник