Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a JSON object which I am repeating with ng-repeat, the keys are strings, and the values are an array. I am listing each of the values as a checkbox. I would like to create a second object which contains a list of only the checkboxes that are checked. I want to preserve the structure of the object with keys and values.

I'm unsure how to bind this to a model properly so that the structure is preserved.

http://jsfiddle.net/NDFc2/3/

This is my HTML

<h3 >Dynamic data binding in AngularJS</h3>
<div ng-app ng-controller="Controller" class="container">
    <h4>Inputs</h4>
    <ul ng-repeat="(parent, values) in inputs">
        <span>{{parent}} : </span>
        <li ng-repeat="value in values"><label>{{value}}
            <input type="checkbox" ng-model="output[parent]" ng-checked="output[parent]" value="value" >                               
            </input></label>
        </li>
    </ul>    

    <h4>Outputs</h4>
    <ul ng-repeat="(key,value) in inputs">
        <li>
            {{key}} : {{output[key]}}
        </li>
    </ul>
</div>

and my JS

function Controller($scope) {
    $scope.output = {};
    $scope.inputs = {'category': ['one','two','three'], 'color':['blue','green']};
}

Is there some simple way to do this? I have the feeling that I'm missing something minor and this will all work nicely.

share|improve this question

2 Answers 2

up vote 2 down vote accepted

My examples have your angular logic in the recommended syntax (non-global). There were also several issues with your markup that I have corrected.

In this example, ng-model="x" is a placeholder that I don't use, but ng-model must be present or an error is thrown. I am using ng-change to handle the link between the checkboxes and $scope.outputs.

Live demo here (click).

Markup:

<div ng-app="myApp" ng-controller="myCtrl">
  <h3 >Dynamic data binding AngularJS</h3>
  <h4>Inputs</h4>
  <ul>
    <li ng-repeat="(typeKey, typeVal) in inputs">
      <span>{{typeKey}} : </span>
      <ul>
        <li ng-repeat="value in typeVal">
          <label>{{value}}
            <input
              type="checkbox"
              ng-model="x"
              ng-change="setOutput(typeKey, $index, value)"
            >
          </label>
        </li>
      </ul>
    </li>
  </ul>    

  <h4>Outputs</h4>
  <ul ng-repeat="(key,value) in inputs">
    <li>{{key}} : {{outputs[key]}}</li>
  </ul>
</div>

JavaScript:

var app = angular.module('myApp', []);

app.controller('myCtrl', function($scope) {
  $scope.outputs = {};
  $scope.inputs = {
    'category': ['one','two','three'],
    'color':['blue','green']
  };
  $scope.setOutput = function(typeKey, $index, value) {
    $scope.outputs[typeKey] = $scope.outputs[typeKey] || [];
    $scope.outputs[typeKey][$index] = value;
  };
});

Another Solution

Live demo here (click).

First, I used ng-init to dynamically add the first-level properties from inputs to outputs. Then you just needed to set your ng-model and ng-checked properties to the correct location in outputs.

Markup:

<div ng-app="myApp" ng-controller="myCtrl">
  <h3 >Dynamic data binding AngularJS</h3>
  <h4>Inputs</h4>
  <ul>
    <li 
      ng-repeat="(typeKey, typeVal) in inputs"
      ng-init="outputs[typeKey] = outputs[typeKey] || {}">
      <span>{{typeKey}} : </span>
      <ul>
        <li ng-repeat="value in typeVal">
          <label>{{value}}
            <input
              type="checkbox"
              ng-model="outputs[typeKey][value]"
              ng-checked="outputs[typeKey][value]"
              value="outputs[typeKey][value]"
            >
          </label>
        </li>
      </ul>
    </li>
  </ul>    

  <h4>Outputs</h4>
  <ul ng-repeat="(key,value) in inputs">
    <li>{{key}} : {{outputs[key]}}</li>
  </ul>
</div>

JavaScript:

var app = angular.module('myApp', []);

app.controller('myCtrl', function($scope) {
  $scope.outputs = {};
  $scope.inputs = {
    'category': ['one','two','three'],
    'color':['blue','green']
  };
});
share|improve this answer
    
Thanks @m59, both these solutions are great. The first one's output was what I'm really looking for, just an array of text, but the only thing is how does the item get removed when unchecked? –  EliteOctagon Dec 6 '13 at 14:48
1  
@EliteOctagon This will do it. jsbin.com/AkeZiSI/4/edit By the way, the cleanest way to do this is to scrap ng-change and ng-model altogether, then write your own directive, passing the input and output via attributes, then setting up your own $watch to handle the change (via similar logic to what I have in my function). –  m59 Dec 6 '13 at 16:51

You need to bind to the value for the parent, as checkboxes don't work like that. Here's an example:

<h3 >Dynamic data binding in AngularJS</h3>
<div ng-app ng-controller="Controller" class="container">
    <h4>Inputs</h4>
    <ul ng-repeat="(parent, values) in inputs">
        <span>{{parent}} : </span>
        <li ng-repeat="value in values"><label>{{value}}
            <input type="checkbox" ng-model="output[parent][value]" ng+checked="output[parent][value]" value="value" >                               
            </input></label>
        </li>
    </ul>    

    <h4>Outputs</h4>
    <ul ng-repeat="(key,value) in inputs">
        <li>
            {{key}} : {{output[key]}}
        </li>
    </ul>
</div>

And in the controller create the keys beforehand

function Controller($scope) {
    $scope.output = { 'category': {}, color: {} };
    $scope.inputs = {'category': ['one','two','three'], 'color':['blue','green']};
}

jsfiddle: http://jsfiddle.net/5eeVc/

share|improve this answer
    
Great answer. Thanks. –  EliteOctagon Dec 6 '13 at 14:49

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.