Come posso associare all'elenco dei valori della casella di controllo con AngularJS?


670

Ho alcune caselle di controllo:

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

Che vorrei associare a un elenco nel mio controller in modo tale che ogni volta che una casella di controllo viene modificata il controller mantiene un elenco di tutti i valori selezionati, ad esempio ['apple', 'pear'].

ng-model sembra essere in grado di associare il valore di una singola casella di controllo a una variabile nel controller.

C'è un altro modo per farlo in modo da poter associare le quattro caselle di controllo a un elenco nel controller?


23
Deve essere un elenco? Un oggetto funzionerebbe ?: <input type='checkbox' ng-model="checkboxes.apple">, ecc. Il modello sarebbe: {"mela": vero, "arancio": falso, "pera": vero, "naartjie": vero}
Mark Rajcok,

2
Prova la direttiva in questo Repo
Vikas Gautam il

1
Assicurati di guardare oltre la risposta accettata. C'è un'altra risposta che, secondo me, è molto più elegante.
Jason Swett,

3
naartjie!? Questo ti dà solo il boet! : D
Piotr Kula

1
@ppumkin hehe ha appena visto questo. Hai ragione: D
nickponline il

Risposte:


927

Esistono due modi per affrontare questo problema. Utilizzare una matrice semplice o una matrice di oggetti. Ogni soluzione ha i suoi pro e contro. Di seguito ne troverai uno per ogni caso.


Con un array semplice come dati di input

L'HTML potrebbe apparire come:

<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 il codice controller appropriato sarebbe:

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

Pro : la struttura dei dati semplice e la commutazione per nome sono facili da gestire

Contro : Aggiungi / Rimuovi è ingombrante poiché devono essere gestite due liste (input e selezione)


Con una matrice di oggetti come dati di input

L'HTML potrebbe apparire come:

<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 il codice controller appropriato sarebbe:

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

Pro : Aggiungi / rimuovi è molto semplice

Contro : la struttura dei dati un po 'più complessa e la commutazione per nome sono ingombranti o richiedono un metodo di supporto


Demo : http://jsbin.com/ImAqUC/1/


10
Cordiali saluti, invece di iniettare $ filter, puoi iniettare filterFilter e quindi usare come segue: return filterFilter ($ scope.fruits, {checked: true}); I filtri integrati e personalizzati sono registrati con l'iniettore $ con nome filterNameFilter ("filterName" deve essere in corsivo) - $ filterProvider documenti
Mark Rajcok,

24
value="{{fruit.name}}"e ng-checked="fruit.checked"sono superflui, poiché viene utilizzato ng-model.
Mark Rajcok,

3
Ho notato che non è necessario specificare "controllato" nel modello, Angular imposterà automaticamente la proprietà :)
daveoncode

3
Dovrebbe usare ng-change invece di ng-click perché gestisce meglio i casi limite.
amccausl,

2
@ViktorMolokostov Sarebbe utile se invii il modulo tradizionalmente . Significa pubblicarlo nel gestore dell'azione (alcuni script lato server). Con php, un elemento form con un nome simile (usando le parentesi quadre) crea un array nei dati della richiesta. In questo modo è possibile gestire facilmente i frutti selezionati.
Yoshi,

406

Una soluzione semplice:

<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 - questa è sicuramente la risposta. L'ho riscritto per le persone (come me) che lavorano con oggetti: plnkr.co/edit/cqsADe8lKegsBMgWMyB8?p=preview
Kyle

5
Lo faccio proprio come fai tu, ma cosa fa l'abilitato (color,enabled) in colors?
Sebastian,

3
@Sebastian, poiché colorsè un oggetto, quando lo fai iterare - ottieni coppie di (key,value).
Kolypto,

10
Anche se questa risposta mi piace molto! Penso che ci sia un grosso problema con l'utilizzo di oggetti come fonte di dati. Cioè, poiché per definizione l'ordine delle proprietà degli oggetti non è definito, non è possibile fornire un ordine definito quando si visualizzano le caselle di controllo. Ancora +1;)
Yoshi,

2
colorsdovrebbe essere chiamato isSelected, è molto più facile da leggere isSelected[color]rispetto acolors[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);
        }
    };
}

2
Adoro quanto sia semplice, esattamente quello che sto cercando (anche se devo ammettere che la direttiva @vitalets è incredibile). Ho modificato un po 'il codice di Umur per creare questo violino: jsfiddle.net/samurai_jane/9mwsbfuc
samurai_jane

Faccio le parole della Samurai Jane mia! Com'era semplice mostrare ciò di cui avevo bisogno! :)
Francis Rodrigues,

81

Ecco una breve direttiva riutilizzabile che sembra fare quello che stai cercando di fare. L'ho semplicemente chiamato checkList. Aggiorna l'array quando cambiano le caselle di controllo e aggiorna le caselle quando cambia l'array.

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

Ecco un controller e una vista che mostra come si potrebbe fare per usarlo.

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

(I pulsanti dimostrano che la modifica dell'array aggiornerà anche le caselle di controllo.)

Infine, ecco un esempio della direttiva in azione su Plunker: http://plnkr.co/edit/3YNLsyoG4PIBW6Kj7dRK?p=preview


2
Grazie Brandon, questo ha fatto esattamente quello che volevo (e esattamente anche quello che la domanda poneva, a differenza delle altre risposte). L'unica modifica che ho fatto è stata quella di cambiare il tuo "elem.on ('change', function () ..." in "elem.bind ('change', function () ..." in modo da rimuovere la dipendenza da jQuery .
Jonathan Moffatt

Questo è abbastanza pulito, ma in qualche modo distrugge la mia capacità di usare ng-disabled :( Esiste un modo per risolverlo?
Nikolaj Dam Larsen,

Super utile! E ha anche funzionato per me con oggetti anziché matrici sia per l'elenco di sorgenti che per l'elenco di dati!
SteveShaffer,

Sono d'accordo con tutti. Questo è il più utile e senza dubbio riutilizzabile !! Grazie per l'ottimo lavoro. :)
maksbd19

2
Se riscontri problemi con AngularJS> = 1.4.4, controlla github.com/angular/angular.js/issues/13037 : sostituisci value: '@'convalue: '=ngValue'
tanguy_k il

66

Sulla base delle risposte in questo thread ho creato una direttiva modello-elenco di controllo che copre tutti i casi:

  • semplice serie di primitivi
  • array di oggetti (scegli id ​​o intero oggetto)
  • iterazione delle proprietà dell'oggetto

Per il caso iniziale sarebbe:

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

Sembra quello di cui ho bisogno. C'è qualche possibilità che tu possa spiegare come usarlo quando ottieni i dati in modo asincrono? Quella parte mi confonde.
Dan Cancro,

Dopo aver ottenuto i dati in modo asincrono, è sufficiente modificare il modello checlist nell'ambito, nell'esempio sopra selectedFruits.
Adrian Ber,

11

L'uso di una stringa di $indexpuò aiutare a utilizzare una hashmap dei valori selezionati:

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

In questo modo l'oggetto ng-model viene aggiornato con la chiave che rappresenta l'indice.

$scope.someObject = {};

Dopo un po ' $scope.someObjectdovrebbe apparire qualcosa di simile:

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

Questo metodo non funzionerà in tutte le situazioni, ma è facile da implementare.


Questa è una soluzione molto elegante e si adatta al mio caso (usando AJAX)
Stephan Ryer il

usa il metodo del bacio
Geomorillo,

8

Poiché hai accettato una risposta in cui un elenco non è stato utilizzato, suppongo che la risposta alla mia domanda di commento sia "No, non deve essere un elenco". Ho anche avuto l'impressione che forse stavi estendendo il lato server HTML, dal momento che "HTML" è presente nel tuo HTML di esempio (questo non sarebbe necessario se ng-model fosse usato per modellare le tue caselle di controllo).

Ad ogni modo, ecco cosa avevo in mente quando ho posto la domanda, anche supponendo che tu stia generando il lato server 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 consente all'HTML generato sul lato server di impostare inizialmente determinate caselle di controllo.

Violino .


8

Penso che la soluzione più semplice sarebbe usare 'select' con 'multiple' specificato:

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

Altrimenti, penso che dovrete elaborare l'elenco per costruirlo ( $watch()inging il modello array bind con caselle di controllo).


3
Sta chiedendo un elenco di caselle di controllo, eppure gli stai dicendo di selezionare con le opzioni. Che è completamente diverso.
CrazySabbath,

@CrazySabbath: eppure non capisci che sta suggerendo una soluzione alternativa e questa risposta ha aiutato altre 6 persone come "soluzione alternativa"
curiousBoy,

5

Ho adattato la risposta accettata di Yoshi per gestire oggetti complessi (anziché stringhe).

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

Esempio di lavoro: http://jsfiddle.net/tCU8v/


1
Non dovresti mai averne uno <input type="checkbox">senza confezione o abbinamento <label>! Ora i tuoi utenti devono fare clic sulla casella di controllo effettiva anziché sul testo accanto alla casella di controllo, che è molto più difficile ed è scarsa usabilità.
Scott,

5

Un'altra semplice direttiva potrebbe essere come:

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

Il controller:

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

Sto anche includendo un Plunker: http://plnkr.co/edit/XnFtyij4ed6RyFwnFN6V?p=preview


5

La seguente soluzione sembra una buona opzione,

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

E nel modello di controller il valore fruitssarà così

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

più sto guardando questi esempi sembra che dovrò mappare il mio array in un array di oggetti.
Winnemucca,

4

Non devi scrivere tutto quel codice. AngularJS manterrà il modello e le caselle di controllo sincronizzati semplicemente usando ngTrueValue e ngFalseValue

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

Snippet di codice:

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

Questo non è ciò che l'OP chiede.
bfontaine,

Associare caselle di controllo a un elenco è ciò che è stato chiesto e che cosa ho fatto. L'array può essere modificato per adattarsi all'applicazione. Il punto è che le caselle di controllo sono associate. ngTrueValue e ngFalseValue possono anche essere usati per mappare un secondo array che elenca solo altri attributi, come i nomi.
Paul B. Hartzog,

OP desidera un elenco di valori controllati, non un elenco di tutti i valori, selezionato e deselezionato.
bfontaine,

4

Dai un'occhiata a questa direttiva che gestisce efficacemente gli elenchi di caselle di controllo. Spero che funzioni per te. Modello CheckList


4

C'è un modo per lavorare direttamente sull'array e usare contemporaneamente ng-model ng-model-options="{ getterSetter: true }".

Il trucco è usare una funzione getter / setter nel tuo modello ng. In questo modo è possibile utilizzare un array come modello reale e "falsificare" i booleani nel modello di input:

<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 Non dovresti usare questo metodo se le tue matrici sono grandi come myGetterSetterverrà chiamato molte volte.

Per ulteriori informazioni, consultare https://docs.angularjs.org/api/ng/directive/ngModelOptions .


3

Mi piace la risposta di Yoshi. L'ho migliorato in modo da poter utilizzare la stessa funzione per più elenchi.

<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 hai più caselle di controllo sullo stesso modulo

Il codice del controller

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

Visualizza codice

<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

Ispirato al post di Yoshi sopra. Ecco il 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

Sulla base del mio altro post qui , ho fatto una direttiva riutilizzabile.

Dai un'occhiata al repository 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

Nel codice HTML (supponendo che le caselle di controllo siano nella prima colonna di ogni riga di una tabella).

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

Nel controllers.jsfile:

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

Ecco un'altra soluzione. Il lato positivo della mia soluzione:

  • Non necessita di orologi aggiuntivi (che potrebbero avere un impatto sulle prestazioni)
  • Non richiede alcun codice nel controller per mantenerlo pulito
  • Il codice è ancora piuttosto breve
  • Richiede pochissimo codice per essere riutilizzato in più punti perché è solo una direttiva

Ecco la direttiva:

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

Alla fine quindi usalo così:

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

E questo è tutto quello che c'è. L'unica aggiunta è l' checkbox-array-setattributo.


3

È possibile combinare AngularJS e jQuery. Ad esempio, è necessario definire un array $scope.selected = [];nel controller.

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

È possibile ottenere un array che possiede gli elementi selezionati. Utilizzando il metodo alert(JSON.stringify($scope.selected)), è possibile controllare gli elementi selezionati.


Perfetto! ... questa è la soluzione più semplice usando un array non un oggetto
Mario Campa,

3
Non combinare Jquery e Angular
Jens Alenius

Ciò porterà a buchi nell'array selezionato.
Dai un'occhiata a

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

Dai un'occhiata a questo: checklist-model .

Funziona con matrici e oggetti JavaScript e può utilizzare caselle di controllo HTML statiche, senza 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 il lato JavaScript:

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

1

Un semplice modo HTML per farlo:

<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

Utilizzando questo esempio di @Umur Kontacı, penso di usare per catturare i dati selezionati attraverso un altro oggetto / array, come una pagina di modifica.

Opzioni di cattura nel database

inserisci qui la descrizione dell'immagine

Attiva o disattiva un'opzione

inserisci qui la descrizione dell'immagine

Ad esempio, tutti i colori json in basso:

{
    "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 tipi di oggetto dati, arraycon un oggetto e objectcontenente due / più dati oggetto:

  • Due elementi selezionati catturati nel database:

    [{"id":12,"title":"Branco - #FFFFFF"},{"id":16,"title":"Roxo - #3A0858"}]
  • Un elemento selezionato catturato nel database:

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

E qui, il mio codice 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;
};

Il mio codice 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>

[Modifica] Codice refactored di seguito:

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 chiama il nuovo metodo come di seguito:

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

Questo è tutto!


1

Ho inserito un array nel controller.

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

Sul markup ho messo qualcosa come segue

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

L'output era il seguente, nel controller avevo solo bisogno di verificare se fosse vero o falso; vero per selezionato, assente / falso per non selezionato.

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

Spero che sia di aiuto.


0

Penso che il seguente modo sia più chiaro e utile per ng-ripetizioni nidificate. Dai un'occhiata su Plunker .

Citazione da questa discussione :

<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

Ecco il link jsFillde per lo stesso, http://jsfiddle.net/techno2mahi/Lfw96ja6/ .

Questo utilizza la direttiva che è disponibile per il download all'indirizzo http://vitalets.github.io/checklist-model/ .

È utile avere una direttiva poiché l'applicazione avrà bisogno di questa funzionalità molto spesso.

Il codice è sotto:

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

Il codice HTML non è ben-formato - ci sono più tag di apertura <div>che di chiusura, </div>. Hai lasciato qualcosa fuori?
Peter Mortensen,

0

Prova il mio bambino:

**

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

**

Quindi, per qualsiasi modello ng con caselle di controllo, restituirà una stringa di tutti gli input selezionati:

<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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.