Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bind to complex objects with radios and checkboxes in AngularJS?

Say we have a set of projects exposed via the Project service:

{ id: '123', name: 'Yeoman', watchers: '1233', ... }
{ id: '123', name: 'Grunt', watchers: '4343', ... }

Then, we have a form to choose your favorite project:

Select favorite project:
%label.radio(ng-repeat="project in Project.query()")
  %input(type="radio" ng-model="data.favoriteProject" value="{{project.id}}") {{project.name}}

This sets choices.favoriteProject to the id value of the chosen project. Often, we need to access the related object, not just the id:

John's favorite project:
{{Project.get(data.favoriteProject).name}}

What I'm looking for is a way to bind the radios and checkboxes straight to the object itself, not the id, so we could do

John's favorite project:
{{data.favoriteProject.name}}

instead. This is possible with select directive via ng-options, but how can we do this with radios and checkboxes? I'd still like to use the ids for matching instead of references, if possible.

To clarify, here's an example what I'm looking for

Select favorite project:
%label.radio(ng-repeat="project in Project.query()")
  %input(type="radio" ng-model="data.favoriteProject" value="{{project}}" ng-match="id") {{project.name}}

It says: "Please bind data.favoriteProject to the actual project object and use the id to check if they match (instead of references)".

like image 827
randomguy Avatar asked Jan 15 '13 13:01

randomguy


Video Answer


2 Answers

[Update]

I've completely changed my answer after discovering the ngValue directive, which appears to be undocumented. It allows you to bind objects instead of just strings as values for ngModel on the radio button inputs.

<label ng-repeat="project in projects">
  <input type="radio" ng-model="data.favoriteProject"
    ng-value="project">{{project.name}}</input>
</label>

<p>Your favorite project is {{data.favoriteProject.name}}.</p>

This uses references to check rather than just IDs, but I think in most cases, this is what people will be looking for. If you do very strictly only want to match based on IDs, you can use the [Old Answer], below, or even better, just create a function--e.g. projectById(projectId) that you can use for looking up a project based on its ID.

I've updated the JSFiddle to demonstrate: http://jsfiddle.net/BinaryMuse/pj2GR/


[Old Answer]

Perhaps you can utilize the ng-change attribute of the radio button directive to achieve what you want. Consider this HTML:

<p>Select your favorite project:</p>
<label ng-repeat="project in projects">
  <input type="radio" ng-model="data.favoriteProjectId" value="{{project.id}}"
         ng-change="data.favoriteProject = project">
    {{project.name}}
  </input>
</label>

<p>Your favorite project is {{data.favoriteProject.name}}.</p>

You could also call a function inside ng-change, for example setfavoriteProject(project)--but I did not do that here for simplicity's sake.

Here is a working jsFiddle to demonstrate the technique: http://jsfiddle.net/BinaryMuse/pj2GR/7/

like image 151
Michelle Tilley Avatar answered Sep 28 '22 06:09

Michelle Tilley


No ng-change needed (and I'm not sure, if it is a good practise to write inline-code like this. On the other hand angulars directives are not too far from it theirselves). Why not just do something like this (works with ng-repeat as well):

Fiddle: http://jsfiddle.net/JohannesJo/VeZxh/3/

Code:

<body ng-app="app">
<div ng-controller='controller'>
<input type = "radio" ng-model = "oSelected"  value = "{{aData[0]}}">
<input type = "radio" ng-model = "oSelected"  value = "{{aData[1]}}">
<div>test:     {{oSelected}}</div>
</div>
</body>


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

app.controller('controller', function($scope){
$scope.aData = [
    {o:1},
    {o:2}
];
$scope.oSelected = {};
});

Edit: I maybe should mention that this doesn't work for checkboxes, as value will either be true or false. Also a shared model will lead to all checkboxes either being checked or unchecked at the same time.

like image 35
hugo der hungrige Avatar answered Sep 28 '22 06:09

hugo der hungrige