samurai_jane
samurai_jane

Reputation: 835

Ignore falsey values when binding an array to an object property in AngularJS

I am using Angular 1.4.8 and would like to put only the checked values of a list into an array. This array then needs to be the value of an object property, like this:

myObject = {
  "myArray": [
    "apple",
    "orange",
    "pear"
  ]
}

My HTML:

<div ng-app="myApp">
  <div ng-controller="MainCtrl as vm">
    <form name="myForm">
      <ul>
        <li ng-repeat="fruit in vm.fruits track by $index">
           <label>
              <input type="checkbox" ng-model="vm.myObject.myArray[$index]" ng-true-value="'{{fruit}}'" ng-false-value="undefined" />{{fruit}}
           </label>
         </li>
      </ul>
    </form>
    <pre>myObject = {{vm.myObject | json}}</pre>
  </div>
</div>

My JS:

angular.module('myApp', []);

angular.module('myApp').controller('MainCtrl', function() {
  var vm = this;
  vm.myObject = {
    myArray: []
  }
  vm.fruits = ["apple", "orange", "pear", "naartjie"];
});

For easy reference, see this fiddle.

Note that when you check and then uncheck a list item, the array retains a value of null. I do not want null bound to the array because it adds to its length and this is causing issues with other code.

How can I ignore binding falsey values like null, undefined, etc...?

Upvotes: 1

Views: 139

Answers (4)

samurai_jane
samurai_jane

Reputation: 835

The problem comes down to tracking by $index. Removing $index from this code:

    <li ng-repeat="fruit in vm.fruits track by $index">
       <label>
          <input type="checkbox" ng-model="vm.myObject.myArray[$index]" ng-true-value="'{{fruit}}'" ng-false-value="undefined" />{{fruit}}
       </label>
     </li>

and replacing it with (key, value) like this:

    <li ng-repeat="(key, value) in vm.fruits track by value">
       <label>
          <input type="checkbox" ng-model="vm.myObject.myArray.value[key]" ng-change="vm.insertIntoArray(value)" ng-true-value="'{{value}}'" />{{value}}
       </label>
     </li>

solved my issue.

Although other answers to-date were helpful and contributed to the final solution, none included everything that I needed. See the updated fiddle for more details.

Upvotes: 0

TheNameless
TheNameless

Reputation: 21

You can create a function to add/remove the fruits from array.

Something like this:

vm.insertIntoArray = function(value){
    var index = vm.fruitsArray.indexOf(value);
    if(index === -1){
        vm.fruitsArray.push(value);
    }else{
        vm.fruitsArray.splice(index,1);
    }
}

Also, set ng-change attribute into your checkboxes.

<input type="checkbox" ng-model="vm.myObject.myArray[$index]" ng-change="vm.insertIntoArray(fruit)" ng-value="'{{fruit}}'"/>

Here's a working fiddle: https://jsfiddle.net/fwu045u0/

Upvotes: 1

KreepN
KreepN

Reputation: 8598

Based on your requirements I have implemented something along the lines of what you may want:

vm.boxChecked = function(item){

   var index = vm.myObject.myArray.indexOf(item);    
   if(index !== -1)
       vm.myObject.myArray.splice(index, 1);
   else
    vm.myObject.myArray.push(item);
};

The fiddle also will check any checkbox whose value appears in the myArray on load. You will see it auto checks 'apple' for you as I have put it in the array. IF you wish to remove this functionality, simply remove apple from the array and the ng-checked portion of the directive and the behavior should be as you desire.

Upvotes: 1

T.Gounelle
T.Gounelle

Reputation: 6033

Look at this plunker for the same problem.

You can modify your model to track the selected items by adding some selected property to the original objects, e.g.

<li ng-repeat="fruit in vm.fruits track by $index">
   <label>
      <input type="checkbox" ng-model="fruit.selected" ng-true-value="'{{fruit}}'" ng-false-value="undefined" />{{fruit}}
   </label>
</li>

Then you have several solutions to build the array of selected elements:

  • with a function that filter the fruit array on selected==true property

  • with a watch on the fruits collection that will update the selected array when an item is selected/unselected.

  • by adding `ng-change="toggleSelect(fruit)" in the input and managing a separate list of selected items

Upvotes: 0

Related Questions