1

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

1
  • Based on the way you have your bindings, you are explicitly setting the values of specific indexes with the true/false value bindings. You would either need to adjust the behavior of your html to execute some JS to perform the upkeep of myArray, or adjust your other code to accomodate the null values to get the functionality you want. Commented Dec 15, 2016 at 18:29

4 Answers 4

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

I removed this as the best answer because after looking at it more closely, you removed ng-model from my fiddle but I need ng-model in my solution. According to the angular docs, ng-model cannot be used with ng-checked. If you know of a workaround, please post.
Unfortunately your data structure doesn't support all your requirements. You will have to make some changes to your objects if you wish to use ng-model. If you are tracking by $index in your post: ng-model="vm.myObject.myArray[$index]" you are bound to set an element at some point that is in the in the middle of your fruit collection. If you set $index = 2 for example, there has to be something occupying $index[0-1]. Since I can't see the code that is affected by adding null values to the array, it is hard to fix my answer.
1

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/

3 Comments

This solution works with a minor tweak. You put the value into splice instead of the index. This fiddle based on yours works. jsfiddle.net/fwu045u0
Yeah, sure. I was useing the value instead of the index by mistake. Thanks @RayfenWindspear.
Victor Hugo, great solution. It's just slightly different that what I was looking for (your code pushes to an array but I need that array to be the property of an object). Nonetheless, thank you very much. Seeing how you approach this problem is extremely helpful. @RayfenWindspear, thank you for the edit, I appreciate it.
0

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

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.