Comment puis-je me lier à la liste des valeurs des cases à cocher avec AngularJS?

670

J'ai quelques cases à cocher:

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

Que je voudrais lier à une liste dans mon contrôleur de sorte que chaque fois qu'une case à cocher est modifiée, le contrôleur conserve une liste de toutes les valeurs vérifiées, par exemple ['apple', 'pear'],.

ng-model ne semble pouvoir lier que la valeur d'une seule case à cocher à une variable du contrôleur.

Y a-t-il une autre façon de le faire pour que je puisse lier les quatre cases à cocher à une liste dans le contrôleur?

nickponline
la source
23
Doit-il s'agir d'une liste? Un objet fonctionnerait-il ?: <input type='checkbox' ng-model="checkboxes.apple">, etc. Le modèle serait: {"apple": true, "orange": false, "pear": true, "naartjie": true}
Mark Rajcok
2
Essayez la directive dans ce Repo
Vikas Gautam
1
Assurez-vous de regarder au-delà de la réponse acceptée. Il y a une autre réponse qui, à mon avis, est beaucoup plus élégante.
Jason Swett
3
naartjie!? Cela vous donne juste un coup de pouce! : D
Piotr Kula
1
@ppumkin hehe vient de voir ça. Vous avez raison: D
nickponline

Réponses:

927

Il existe deux façons d'aborder ce problème. Utilisez un simple tableau ou un tableau d'objets. Chaque solution a ses avantages et ses inconvénients. Vous trouverez ci-dessous un pour chaque cas.


Avec un tableau simple comme données d'entrée

Le HTML pourrait ressembler à:

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

Et le code de contrôleur approprié serait:

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

Avantages : La structure de données simple et le basculement par nom sont faciles à gérer

Inconvénients : l'ajout / la suppression est fastidieux car deux listes (l'entrée et la sélection) doivent être gérées


Avec un tableau d'objets comme données d'entrée

Le HTML pourrait ressembler à:

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

Et le code de contrôleur approprié serait:

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

Avantages : ajouter / supprimer est très facile

Inconvénients : structure de données un peu plus complexe et basculement par nom est lourd ou nécessite une méthode d'assistance


Démo : http://jsbin.com/ImAqUC/1/

Yoshi
la source
10
Pour info, au lieu d'injecter $ filter, vous pouvez injecter filterFilter, puis utiliser comme suit: return filterFilter ($ scope.fruits, {vérifié: vrai}); Les filtres
intégrés
24
value="{{fruit.name}}"et ng-checked="fruit.checked"sont superflus, car le modèle ng est utilisé.
Mark Rajcok
3
J'ai remarqué qu'il n'est pas nécessaire de spécifier "vérifié" dans le modèle, Angular définira automatiquement la propriété :)
daveoncode
3
Devrait utiliser ng-change au lieu de ng-click car il traite mieux les cas de bord.
amccausl
2
@ViktorMolokostov Cela serait tout simplement utile si vous soumettiez le formulaire de façon traditionnelle . Cela signifie de le poster dans le gestionnaire d'actions (certains scripts côté serveur). Avec php, un élément de formulaire avec un nom comme celui-ci (en utilisant les crochets) crée un tableau dans les données de la requête. De cette façon, vous pouvez facilement manipuler les fruits sélectionnés.
Yoshi
406

Une solution simple:

<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
la source
57
@kolypto - c'est certainement la réponse. Je l'ai réécrit pour les personnes (comme moi) qui travaillent avec des objets: plnkr.co/edit/cqsADe8lKegsBMgWMyB8?p=preview
Kyle
5
Je le fais comme vous, mais à quoi sert l'activé (color,enabled) in colors?
Sebastian
3
@Sebastian, puisque colorsc'est un objet, quand vous l'itérez - vous obtenez des paires de (key,value).
kolypto du
10
Bien que j'aime beaucoup cette réponse! Je pense qu'il y a un problème majeur avec l'utilisation d'objets comme source de données. C'est-à-dire que, par définition, l'ordre des propriétés des objets n'est pas défini, on ne peut pas fournir un ordre défini lors de l'affichage des cases à cocher. Toujours +1;)
Yoshi
2
colorsdevrait être nommé isSelected, il est beaucoup plus facile à lire isSelected[color]quecolors[color]
Dmitri Zaitsev
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);
        }
    };
}
Umur Kontacı
la source
2
J'adore à quel point c'est simple, exactement ce que je recherche (même si je dois admettre que la directive @vitalets est incroyable). J'ai un peu modifié le code d'Umur pour créer ce violon: jsfiddle.net/samurai_jane/9mwsbfuc
samurai_jane
Je fais les mots de la mine Samurai Jane! Comme c'était simple de montrer ce dont j'avais besoin! :)
Francis Rodrigues
81

Voici une petite directive réutilisable rapide qui semble faire ce que vous cherchez à faire. Je l'ai simplement appelé checkList. Il met à jour le tableau lorsque les cases à cocher changent et met à jour les cases à cocher lorsque le tableau change.

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

Voici un contrôleur et une vue qui montrent comment vous pouvez vous en servir.

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

(Les boutons montrent que la modification de la matrice mettra également à jour les cases à cocher.)

Enfin, voici un exemple de la directive en action sur Plunker: http://plnkr.co/edit/3YNLsyoG4PIBW6Kj7dRK?p=preview

Michelle Tilley
la source
2
Merci Brandon, cela a fait exactement ce que je voulais (et exactement ce que la question demandait aussi, contrairement aux autres réponses). Le seul ajustement que j'ai fait a été de changer votre "elem.on ('change', function () ..." en "elem.bind ('change', function () ..." afin de supprimer la dépendance sur jQuery .
Jonathan Moffatt
C'est assez soigné, mais détruit en quelque sorte ma capacité à utiliser ng-disabled :( Y a-t-il un moyen de résoudre ce problème?
Nikolaj Dam Larsen
Super utile! Et même travaillé pour moi avec des objets au lieu de tableaux pour la liste source et la liste de données!
SteveShaffer
Je suis d'accord avec tout le monde. Celui-ci est le plus utile et sans aucun doute réutilisable !! Merci pour le bon travail. :)
maksbd19
2
Si vous rencontrez des problèmes avec AngularJS> = 1.4.4, consultez github.com/angular/angular.js/issues/13037 : remplacez value: '@'parvalue: '=ngValue'
tanguy_k
66

Sur la base des réponses dans ce fil, j'ai créé une directive de modèle de liste de contrôle qui couvre tous les cas:

  • tableau simple de primitives
  • tableau d'objets (choisissez id ou objet entier)
  • itération des propriétés des objets

Pour le cas du sujet, ce serait:

<label ng-repeat="fruit in ['apple', 'orange', 'pear', 'naartjie']">
    <input type="checkbox" checklist-model="selectedFruits" checklist-value="fruit"> {{fruit}}
</label>
vitalets
la source
Cela ressemble à ce dont j'ai besoin. Y a-t-il une chance que vous puissiez expliquer comment l'utiliser lors de l'obtention asynchrone des données? Cette partie me déroute.
Dan Cancro
Après avoir obtenu les données de manière asynchrone, modifiez simplement le modèle de liste de chèques dans la portée, dans l'exemple ci-dessus selectedFruits.
Adrian Ber
11

L'utilisation d'une chaîne de $indexpeut aider à utiliser une table de hachage des valeurs sélectionnées:

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

De cette façon, l'objet ng-model est mis à jour avec la clé représentant l'index.

$scope.someObject = {};

Après un certain temps $scope.someObjectdevrait ressembler à quelque chose comme:

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

Cette méthode ne fonctionnera pas dans toutes les situations, mais elle est facile à mettre en œuvre.

user2479438
la source
Ceci est une solution très élégante et s'adapte à mon cas (en utilisant AJAX)
Stephan Ryer
utilise la méthode du baiser
Geomorillo
8

Puisque vous avez accepté une réponse dans laquelle aucune liste n'a été utilisée, je suppose que la réponse à ma question de commentaire est "Non, il ne doit pas nécessairement s'agir d'une liste". J'ai également eu l'impression que peut-être vous rendiez le côté serveur HTML, car "vérifié" est présent dans votre exemple HTML (cela ne serait pas nécessaire si ng-model était utilisé pour modéliser vos cases à cocher).

Quoi qu'il en soit, voici ce que j'avais à l'esprit lorsque j'ai posé la question, en supposant également que vous génériez le côté serveur 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 permet au HTML généré côté serveur de définir initialement certaines cases à cocher.

Violon .

Mark Rajcok
la source
8

Je pense que la solution de contournement la plus simple serait d'utiliser 'select' avec 'multiple' spécifié:

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

Sinon, je pense que vous devrez traiter la liste pour construire la liste (en $watch()combinant la liaison du tableau de modèles avec des cases à cocher).

Tosh
la source
3
Il demande une liste de cases à cocher, et pourtant vous lui parlez de sélectionner avec des options. Ce qui est complètement différent.
CrazySabbath
@CrazySabbath: pourtant vous ne comprenez pas qu'il suggère une solution alternative et cette réponse a aidé 6 autres personnes comme une "solution alternative"
curiousBoy
5

J'ai adapté la réponse acceptée de Yoshi pour traiter des objets complexes (au lieu des chaînes).

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

Exemple de travail: http://jsfiddle.net/tCU8v/

Adam
la source
1
Vous ne devriez jamais avoir un <input type="checkbox">sans emballage ou assorti <label>! Maintenant, vos utilisateurs doivent cliquer sur la case à cocher réelle au lieu du texte à côté de la case à cocher, ce qui est beaucoup plus difficile et est une mauvaise utilisation.
Scott
5

Une autre directive simple pourrait être comme:

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

Le controlle:

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

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

J'inclus également un Plunker: http://plnkr.co/edit/XnFtyij4ed6RyFwnFN6V?p=preview

Adrian Stanescu
la source
5

La solution suivante semble être une bonne option,

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

Et dans le modèle du contrôleur, la valeur fruitssera comme ceci

$scope.fruits = [
  {
    "name": "apple",
    "checked": true
  },
  {
    "name": "orange"
  },
  {
    "name": "grapes",
    "checked": true
  }
];
Mohammed Safeer
la source
plus je regarde ces exemples, il semble que je devrai mapper mon tableau en un tableau d'objets.
Winnemucca
4

Vous n'avez pas besoin d'écrire tout ce code. AngularJS gardera le modèle et les cases à cocher synchronisés simplement en utilisant ngTrueValue et ngFalseValue

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

Extrait de code:

<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>
Paul B. Hartzog
la source
Ce n'est pas ce que demande OP.
bfontaine
Lier des cases à cocher à une liste est ce qui a été demandé et ce que j'ai fait. Le tableau peut être modifié pour s'adapter à l'application. Le fait est que les cases à cocher sont liées. ngTrueValue et ngFalseValue peuvent également être utilisés pour mapper vers un deuxième tableau qui répertorie uniquement d'autres attributs, tels que des noms.
Paul B. Hartzog
OP veut une liste de valeurs vérifiées, pas une liste de toutes les valeurs, cochée et décochée.
bfontaine
4

Découvrez cette directive qui gère efficacement les listes de cases à cocher. J'espère que ça marche pour vous. Modèle CheckList

DSB
la source
4

Il existe un moyen de travailler directement sur le tableau et d'utiliser simultanément ng-model via ng-model-options="{ getterSetter: true }" .

L'astuce consiste à utiliser une fonction getter / setter dans votre modèle ng. De cette façon, vous pouvez utiliser un tableau comme modèle réel et «simuler» les booléens dans le modèle d'entrée:

<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 Vous ne devez pas utiliser cette méthode si vos tableaux sont volumineux, comme myGetterSetteron l'appellera souvent.

Pour plus d'informations à ce sujet, voir https://docs.angularjs.org/api/ng/directive/ngModelOptions .

David
la source
3

J'aime la réponse de Yoshi. Je l'ai amélioré pour que vous puissiez utiliser la même fonction pour plusieurs listes.

<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
la source
3

Si vous avez plusieurs cases à cocher sur le même formulaire

Le code du contrôleur

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

Afficher le code

<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>        
Rama Krshna Ila
la source
3

Inspiré du post de Yoshi ci-dessus. Voici le 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="[email protected]" data-semver="3.0.0" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script>
      <script data-require="[email protected]" data-semver="1.5.6" src="https://code.angularjs.org/1.5.6/angular.min.js"></script>
      <script src="script.js"></script>
   </body>

</html>

Vikas Gautam
la source
3

Sur la base de mon autre article ici , j'ai créé une directive réutilisable.

Découvrez le référentiel 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="[email protected]" data-semver="3.0.0" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script>
      <script data-require="[email protected]" data-semver="1.5.6" src="https://code.angularjs.org/1.5.6/angular.min.js"></script>
      <script src="script.js"></script>
   </body>

</html>

Vikas Gautam
la source
3

Dans le code HTML (en supposant que les cases à cocher se trouvent dans la première colonne de chaque ligne d'un tableau).

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

Dans le controllers.jsdossier:

// 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
la source
3

Voici encore une autre solution. L'avantage de ma solution:

  • Il n'a pas besoin de montres supplémentaires (ce qui peut avoir un impact sur les performances)
  • Il ne nécessite aucun code dans le contrôleur pour le garder propre
  • Le code est encore un peu court
  • Il nécessite très peu de code pour être réutilisé à plusieurs endroits car il ne s'agit que d'une directive

Voici la directive:

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

À la fin, utilisez-le simplement comme ceci:

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

Et c'est tout ce qu'il y a. Le seul ajout est l' checkbox-array-setattribut.

yankee
la source
3

Vous pouvez combiner AngularJS et jQuery. Par exemple, vous devez définir un tableau,, $scope.selected = [];dans le contrôleur.

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

Vous pouvez obtenir un tableau contenant les éléments sélectionnés. En utilisant la méthode alert(JSON.stringify($scope.selected)), vous pouvez vérifier les éléments sélectionnés.

Dahai
la source
Parfait! ... c'est la solution la plus simple en utilisant un tableau et non un objet
Mario Campa
3
Ne combinez pas Jquery et Angular
Jens Alenius
Cela entraînera des trous dans le tableau sélectionné. Voir cet article
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);
        }    
       }
     }   
   })
vijay007
la source
1

Jetez un oeil à ceci: modèle de liste de contrôle .

Il fonctionne avec des tableaux et des objets JavaScript et peut utiliser des cases à cocher HTML statiques, sans 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>

Et le côté JavaScript:

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

Une façon HTML simple de le faire:

<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')">

Matt Carroll
la source
1

En utilisant cet exemple de @Umur Kontacı, je pense qu'en utilisant pour capturer les données sélectionnées dans un autre objet / tableau, comme une page d'édition.

Options de capture dans la base de données

entrez la description de l'image ici

Basculer une option

entrez la description de l'image ici

À titre d'exemple, toutes les couleurs json ci-dessous:

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

Et 2 types d'objet de données, arrayavec un objet etobject contenant deux / plusieurs données d'objet:

  • Deux éléments sélectionnés capturés dans la base de données:

    [{"id":12,"title":"Branco - #FFFFFF"},{"id":16,"title":"Roxo - #3A0858"}]
  • Un élément sélectionné capturé dans la base de données:

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

Et ici, mon code 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;
};

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

[Modifier] Code refactorisé ci-dessous:

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

Et appelez une nouvelle méthode comme ci-dessous:

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

C'est ça!

Francis Rodrigues
la source
1

J'ai mis un tableau dans le contrôleur.

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

Sur le balisage, j'ai mis quelque chose comme suit

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

La sortie était la suivante, dans le contrôleur j'avais juste besoin de vérifier si c'était vrai ou faux; vrai pour coché, absent / faux pour non coché.

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

J'espère que cela t'aides.

Mahib
la source
0

Je pense que la manière suivante est plus claire et utile pour les répétitions ng imbriquées. Découvrez-le sur Plunker .

Citation de ce fil :

<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
la source
0

Voici le lien jsFillde pour le même, http://jsfiddle.net/techno2mahi/Lfw96ja6/ .

Celui-ci utilise la directive qui est disponible en téléchargement sur http://vitalets.github.io/checklist-model/ .

C'est une bonne chose d'avoir une directive car votre application aura souvent besoin de cette fonctionnalité.

Le code est ci-dessous:

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');
  };
});
Mahendra
la source
Le code HTML est pas bien formé - il y a plus de balises d'ouverture <div>que la fermeture, </div>. Avez-vous oublié quelque chose?
Peter Mortensen
0

Essayez mon bébé:

**

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

**

Ensuite, pour tout modèle ng avec des cases à cocher, il retournera une chaîne de toutes les entrées que vous avez sélectionnées:

<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
Samantha Guergenenov
la source