Como vincular à lista de valores da caixa de seleção com o AngularJS?


670

Eu tenho algumas caixas de seleção:

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

Que eu gostaria de vincular a uma lista no meu controlador, para que, sempre que uma caixa de seleção for alterada, o controlador mantenha uma lista de todos os valores verificados, por exemplo ['apple', 'pear'],.

O ng-model parece apenas ser capaz de vincular o valor de uma única caixa de seleção a uma variável no controlador.

Existe outra maneira de fazer isso para que eu possa vincular as quatro caixas de seleção a uma lista no controlador?


23
Tem que ser uma lista? Será que um trabalho objeto ?: <input type='checkbox' ng-model="checkboxes.apple">, etc. Modelo seria: { "maçã": true, "laranja": false, "pêra": true "naartjie": true}
Mark Rajcok

2
Experimente a directiva neste Repo
Vikas Gautam

1
Certifique-se de olhar além da resposta aceita. Há outra resposta que, na minha opinião, é muito mais elegante.
precisa

3
naartjie!? Isso apenas te deixa boet! : D
Piotr Kula

1
@ppumkin hehe acabou de ver isso. Você está certo: D
nickponline

Respostas:


927

Existem duas maneiras de abordar esse problema. Use uma matriz simples ou uma matriz de objetos. Cada solução tem prós e contras. Abaixo, você encontrará um para cada caso.


Com uma matriz simples como dados de entrada

O HTML pode se parecer com:

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

E o código do controlador apropriado seria:

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

Prós : estrutura de dados simples e alternar por nome é fácil de manusear

Contras : Adicionar / remover é complicado, pois duas listas (entrada e seleção) precisam ser gerenciadas


Com uma matriz de objetos como dados de entrada

O HTML pode se parecer com:

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

E o código do controlador apropriado seria:

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

Prós : Adicionar / remover é muito fácil

Contras : A estrutura de dados e a alternância de nomes um pouco mais complexas são complicadas ou exigem um método auxiliar


Demonstração : http://jsbin.com/ImAqUC/1/


10
Para sua informação, em vez de injetar $ filter, você pode injetar filterFilter e, em seguida, use o seguinte: return filterFilter ($ scope.fruits, {selected: true}); Os filtros internos e personalizados são registrados com o injetor $ com o nome filterNameFilter ("filterName" deve estar em itálico) - $ filterProvider docs
Mark Rajcok

24
value="{{fruit.name}}"e ng-checked="fruit.checked"são supérfluos, já que o ng-model é usado.
Mark Rajcok

3
Notei que não há necessidade de especificar "marcado" no modelo, angular irá definir a propriedade automaticamente :)
daveoncode

3
Deve usar ng-change em vez de ng-click, pois lida melhor com casos extremos.
amccausl

2
@ViktorMolokostov Isso seria útil se você enviasse o formulário tradicionalmente . Significando publicá-lo no manipulador de ações (algum script do lado do servidor). Com o php, um elemento de formulário com um nome como esse (usando colchetes) cria uma matriz nos dados da solicitação. Dessa forma, você pode manipular facilmente as frutas selecionadas.
Yoshi

406

Uma solução simples:

<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


57
@ kolypto - esta é definitivamente a resposta. Eu o reescrevi para pessoas (como eu) que estão trabalhando com objetos: plnkr.co/edit/cqsADe8lKegsBMgWMyB8?p=preview
Kyle

5
Faço-o exatamente como você faz, mas o que o ativado (color,enabled) in colorsfaz?
Sebastian

3
@ Sebastian, já que colorsé um objeto, quando você o itera - você recebe pares de (key,value).
Kolypto

10
Embora eu goste muito desta resposta! Eu acho que há um grande problema com o uso de objetos como fonte de dados. Ou seja, porque, por definição, a ordem das propriedades dos objetos é indefinida, não é possível fornecer uma ordem definida ao exibir as caixas de seleção. Ainda +1;)
Yoshi

2
colorsdeve ser nomeado isSelected, é muito mais fácil de ler isSelected[color]do quecolors[color]
Dmitri Zaitsev

86
<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
Adoro como isso é simples, exatamente o que estou procurando (embora eu deva admitir que a diretiva @vitalets é incrível). Eu modifiquei o código do Umur um pouco para criar esta violino: jsfiddle.net/samurai_jane/9mwsbfuc
samurai_jane

Eu faço as palavras da mina Samurai Jane! Quão simples foi mostrar exatamente o que eu precisava! :)
Francis Rodrigues

81

Aqui está uma pequena diretiva reutilizável rápida que parece fazer o que você está procurando. Eu simplesmente chamei isso checkList. Ele atualiza a matriz quando as caixas de seleção mudam e atualiza as caixas de seleção quando a matriz é alterada.

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

Aqui está um controlador e uma exibição que mostra como você pode usá-lo.

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

(Os botões demonstram que alterar a matriz também atualizará as caixas de seleção.)

Finalmente, aqui está um exemplo da diretiva em ação no Plunker: http://plnkr.co/edit/3YNLsyoG4PIBW6Kj7dRK?p=preview


2
Obrigado Brandon, isso fez exatamente o que eu queria (e exatamente o que a pergunta também pedia, diferente das outras respostas). O único ajuste que fiz foi alterar seu "elem.on ('change', function () ..." para "elem.bind ('change', function () ...") para remover a dependência do jQuery #
23713 Jonathan Moffatt

Este é bastante puro, mas de alguma forma destrói a minha capacidade de usar ng-disabled :( Existe alguma maneira eu posso corrigir isso?
Nikolaj Dam Larsen

Super útil! E até trabalhou para mim com objetos em vez de matrizes para a lista de fontes e a lista de dados!
SteveShaffer

Eu concordo com todos. Este é o mais útil e sem dúvida reutilizável !! Obrigado pelo bom trabalho. :)
maksbd19

2
Se você estiver tendo problemas com o AngularJS> = 1.4.4, consulte github.com/angular/angular.js/issues/13037 : replace value: '@'byvalue: '=ngValue'
tanguy_k

66

Com base nas respostas deste tópico, criei a diretiva de modelo de lista de verificação que cobre todos os casos:

  • matriz simples de primitivos
  • matriz de objetos (escolha o ID ou o objeto inteiro)
  • iteração de propriedades do objeto

Para o caso de iniciador de tópicos, seria:

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

Parece o que eu preciso. Existe alguma chance de você explicar como usá-lo ao obter os dados de forma assíncrona? Essa parte é confusa para mim.
Dan Cancro 12/12

Depois de obter os dados de forma assíncrona, modifique o modelo checlist no escopo, no exemplo acima selectedFruits.
Adrian Ber

11

O uso de uma cadeia de caracteres $indexpode ajudar a usar um mapa de hash dos valores selecionados:

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

Dessa forma, o objeto ng-model é atualizado com a chave que representa o índice.

$scope.someObject = {};

Depois de um tempo $scope.someObjectdeve ser algo como:

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

Este método não funcionará para todas as situações, mas é fácil de implementar.


Esta é uma solução muito elegante e se encaixa meu caso (usando AJAX)
Stephan Ryer

usa o método beijo
Geomorillo

8

Como você aceitou uma resposta na qual uma lista não foi usada, assumirei que a resposta para minha pergunta de comentário é "Não, não precisa ser uma lista". Eu também tive a impressão de que talvez você estivesse renderizando o lado do servidor HTML, já que "marcado" está presente no seu exemplo de HTML (isso não seria necessário se ng-model fosse usado para modelar suas caixas de seleção).

Enfim, eis o que eu tinha em mente quando fiz a pergunta, assumindo também que você estava gerando o lado do servidor 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>

O ng-init permite que o HTML gerado pelo servidor defina inicialmente determinadas caixas de seleção.

Violino .


8

Eu acho que a solução mais fácil seria usar 'select' com 'multiple' especificado:

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

Caso contrário, acho que você terá que processar a lista para construí-la ( $watch()ligando a matriz do modelo às caixas de seleção).


3
Ele está pedindo uma lista de opções e, no entanto, você está dizendo a ele sobre as opções de seleção. O que é completamente diferente.
CrazySabbath

@CrazySabbath: ainda que você não está entendendo que ele sugerindo uma solução alternativa e esta resposta ajudou 6 outras pessoas como uma "solução alternativa"
curiousBoy

5

Eu adaptei a resposta aceita de Yoshi para lidar com objetos complexos (em vez de cadeias).

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

Exemplo de trabalho: http://jsfiddle.net/tCU8v/


1
Você nunca deve ter um <input type="checkbox">sem um embrulho ou correspondência <label>! Agora, os usuários precisam clicar na caixa de seleção real, em vez do texto ao lado da caixa de seleção, o que é muito mais difícil e tem má usabilidade.
Scott

5

Outra diretiva simples pode ser como:

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

O controlador:

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 = [];
    };
}]);

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

Também estou incluindo um Plunker: http://plnkr.co/edit/XnFtyij4ed6RyFwnFN6V?p=preview


5

A solução a seguir parece ser uma boa opção,

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

E no valor do modelo do controlador fruitsserá assim

$scope.fruits = [
  {
    "name": "apple",
    "checked": true
  },
  {
    "name": "orange"
  },
  {
    "name": "grapes",
    "checked": true
  }
];

quanto mais eu estou vendo esses exemplos, parece que terei que mapear minha matriz em uma matriz de objetos.
Winnemucca

4

Você não precisa escrever todo esse código. O AngularJS manterá o modelo e as caixas de seleção sincronizadas simplesmente usando ngTrueValue e ngFalseValue

Codepen aqui: http://codepen.io/paulbhartzog/pen/kBhzn

Fragmento de código:

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

Não é isso que o OP está pedindo.
bfontaine

Vincular caixas de seleção a uma lista é o que foi solicitado e o que eu fiz. A matriz pode ser modificada para se adequar ao aplicativo. O ponto é que as caixas de seleção estão vinculadas. ngTrueValue e ngFalseValue também podem ser usados ​​para mapear para uma segunda matriz que lista apenas outros atributos, como nomes.
Paul B. Hartzog 4/04

O OP deseja uma lista de valores verificados, não uma lista de todos os valores, marcada e desmarcada.
Bfontaine

4

Confira esta diretiva que gerencia efetivamente listas de caixas de seleção. Espero que funcione para você. Modelo CheckList


4

Existe uma maneira de trabalhar diretamente na matriz e usar o ng-model ao mesmo tempo ng-model-options="{ getterSetter: true }".

O truque é usar uma função getter / setter no seu modelo ng. Dessa forma, você pode usar uma matriz como seu modelo real e "falsificar" os booleanos no modelo da entrada:

<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 Você não deve usar esse método se suas matrizes forem grandes, como myGetterSetterserá chamado muitas vezes.

Para saber mais, consulte https://docs.angularjs.org/api/ng/directive/ngModelOptions .


3

Eu gosto da resposta de Yoshi. Eu o aprimorei para que você possa usar a mesma função para várias listas.

<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


3

Se você tiver várias caixas de seleção no mesmo formulário

O código do controlador

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

Ver código

<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

Inspirado no post de Yoshi acima. Aqui está o plnkr .

(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

Com base no meu outro post aqui , fiz uma diretiva reutilizável.

Confira o repositório do 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

No HTML (supondo que as caixas de seleção estejam na primeira coluna de cada linha de uma tabela).

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

No controllers.jsarquivo:

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

3

Aqui está mais uma solução. A vantagem da minha solução:

  • Não precisa de relógios adicionais (que podem afetar o desempenho)
  • Não requer nenhum código no controlador para mantê-lo limpo
  • O código ainda é um pouco curto
  • Requer muito pouco código para reutilizar em vários lugares, porque é apenas uma diretiva

Aqui está a diretiva:

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

No final, basta usá-lo assim:

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

E isso é tudo o que existe. A única adição é o checkbox-array-setatributo


3

Você pode combinar AngularJS e jQuery. Por exemplo, você precisa definir uma matriz $scope.selected = [];, no controlador.

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

Você pode obter uma matriz que possui os itens selecionados. Usando o método alert(JSON.stringify($scope.selected)), você pode verificar os itens selecionados.


Perfeito! ... esta é a solução mais simples usando uma matriz não um objeto
Mario Campa

3
Não combine Jquery e Angular
Jens Alenius

Isso levará a buracos na matriz selecionada. Verifique este post
Vikas Gautam

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

1

Dê uma olhada neste: checklist-model .

Funciona com matrizes JavaScript e objetos e pode usar caixas de seleção HTML estáticas, sem 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>

E o lado do JavaScript:

var app = angular.module("app", ["checklist-model"]);
app.controller('Ctrl4a', function($scope) {
    $scope.roles = [];
});

1

Uma única maneira simples de fazer isso em 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

Usando este exemplo do @Umur Kontacı, penso em usar para capturar dados selecionados em outro objeto / matriz, como uma página de edição.

Opções de captura no banco de dados

insira a descrição da imagem aqui

Alterne uma opção

insira a descrição da imagem aqui

Como exemplo, todas as cores json abaixo:

{
    "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"
        }
    ]
}

E 2 tipos de objeto de dados, arraycom um objeto e objectcontendo dois / mais dados de objeto:

  • Dois itens selecionados foram capturados no banco de dados:

    [{"id":12,"title":"Branco - #FFFFFF"},{"id":16,"title":"Roxo - #3A0858"}]
  • Um item selecionado foi capturado no banco de dados:

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

E aqui, meu código 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;
};

Meu código 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>

[Editar] Código refatorado abaixo:

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

E chame o novo método como abaixo:

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

É isso aí!


1

Eu coloquei uma matriz no controlador.

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

Na marcação, coloquei algo como seguir

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

A saída foi a seguinte, no controlador, eu só precisava verificar se é verdadeiro ou falso; verdadeiro para marcado, ausente / falso para não marcado.

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

Espero que isto ajude.


0

Eu acho que a seguinte maneira é mais clara e útil para repetições ng aninhadas. Confira no Plunker .

Citação deste tópico :

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

0

Aqui está o link jsFillde para o mesmo, http://jsfiddle.net/techno2mahi/Lfw96ja6/ .

Isso usa a diretiva que está disponível para download em http://vitalets.github.io/checklist-model/ .

É bom ter uma diretiva, pois seu aplicativo precisará dessa funcionalidade com muita frequência.

O código está abaixo:

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

O HTML não está bem formado - há mais tags de abertura do <div>que fechamento </div>,. Você deixou algo de fora?
Peter Mortensen

0

Tente meu bebê:

**

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

**

Então, para qualquer modelo ng com caixas de seleção, ele retornará uma sequência de todas as entradas que você selecionou:

<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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.