Pablo
Pablo

Reputation: 2154

AngularJS not keeping selected items from checkbox list in a form

I'd like to save a list of selected items from a checkbox list, generated with an angular service as follows.

Unfortunately, my "job" object only persists the state of the last selected checkbox, instead of the id values of all of the selected checkboxes in the list.

Could anyone tell me what am I doing wrong please?

Plunker with the entire example: http://plnkr.co/edit/znLy9EqUMZN6kRzNnl07?p=preview

<script type="text/javascript">
var app = angular.module('helloWorldApp', []);

app.service('HelloWorldService', function() {
  var model = this;
  var people = [{
    "id": 0,
    "firstName": "John",
    "lastName": "Doe",
    "expertise": "Programmer",
    "checked": false
  }, {
    "id": 1,
    "firstName": "Mary",
    "lastName": "Jane",
    "expertise": "Manager",
    "checked": false
  }];

  model.getPeople = function() {
    return people;
  };
});

app.controller('HelloWorldController', ['$scope', 'HelloWorldService',
  function($scope, HelloWorldService) {
    var helloWorld = this;
    // why this does not work?
    // helloWorld.people = function() { return HelloWorldService.getPeople(); };
    // why this one works?
    helloWorld.people = HelloWorldService.getPeople();
    $scope.selectedPeople = [];
    helloWorld.selectedPeople = [];

    $scope.createNewJob = function() {
      console.log("Object: " + JSON.stringify($scope.job));
    };

    $scope.addPerson = function(id) {
      // how can I keep a list of selected people in my ng-model object?
      //helloWorld.selectedPeople.push(id + " selected");
      $scope.selectedPeople.push(id + " selected");
      helloWorld.selectedPeople = $scope.selectedPeople;
      console.log($scope.selectedPeople);
    }
  }
]);

  <tbody ng-controller="HelloWorldController as helloWorld">
    <tr ng-repeat="person in helloWorld.people">
      <td>
        <input type="checkbox" name="peopleList[]" ng-model="job.selectedPeople" ng-click="addPerson(person.id)" value="{{person.id}}" />
        <label>{{person.firstName}} {{person.lastName}}</label>
      </td>
      <td>
        {{person.expertise}}
      </td>
    </tr>
  </tbody>

Upvotes: 0

Views: 884

Answers (2)

Mathieu Bertin
Mathieu Bertin

Reputation: 1624

This a running code, your principal mistake was to use an ng-model for each input and it was the controller scope that you could put on the form element.

I use ng-checked directive in order to define if the checkbox has to be checked or not.

  $scope.isChecked = function (id) {
     return $scope.selectedPeople.indexOf(id) > -1;
  }

and html

<input type="checkbox" name="peopleList[]" ng-checked="isChecked(person.id)" ng-click="addPerson(person.id)" />

This is the code, hope that will help you.

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

Upvotes: 1

James Waddington
James Waddington

Reputation: 2905

Currently, the exact same model (job.selectedPeople) is assigned to every row, and the state of the checkbox is added on to the end of selectedPeople every time it's clicked. This means selectedPeople is acting as a history of all clicks, not a record of the current state.

You can use $index to specify that each row in your repeat is modeled on its own array element:

ng-model="selectedPeople[$index]"

You can then remove this because the array will be automatically updated by data binding:

$scope.selectedPeople.push(id + " selected");
helloWorld.selectedPeople = $scope.selectedPeople;

More generally I think it would help to have clearer separation of jobs and people, but hopefully the above will help.

Upvotes: 1

Related Questions