Binding ng-model to ng-repeat not working - javascript

I'm trying to bind ng-model dynamically with ng-repeat, but it doesn't seem to work. input.placeholder and input.fa both work as expected, but I can't seem to bind ng-model to anything as it gives me an error.
The relevant HTML
<li class="animate-repeat" ng-repeat="input in accountInfo">
<div class="input-group input-group-icon">
<input type="text" placeholder="{{input.placeholder}}" ng-model="{{input.model}}"/>
<div class="input-icon"><i class="fa {{input.fa}}"></i></div>
</div>
</li>
My accountInfo array of objects.
$scope.accountInfo = [
{
model: 'user.fullName',
placeholder: 'Full Name',
fa: 'fa-user',
},
{
model: 'user.email',
placeholder: 'Email Address',
fa: 'fa-envelope',
},
{
model: 'user.password',
placeholder: 'Password',
fa: 'fa-key',
},
{
model: 'user.phone',
placeholder: 'Phone Number',
fa: 'fa-phone',
},
];
The error i get
error link
Please help

ng-model is not interpolated; you shouldn't wrap it in {{. So,
<input ... ng-model="input.model">
should work fine.
Edit: Sorry, I didn't see that you were trying to dynamically set the ng-model -- my apologies.
The easiest solution would be to use references in the accountInfo, if user is available in that scope:
$scope.accountInfo = [{
model: user.fullName,
placeholder: 'Full Name',
...
Otherwise, you can declare an object on the $scope and manually link it to the models:
// ... some place without access to `user`
$scope.accountInfo = [{
model: 'fullName',
placeholder: 'Full Name',
...
// some place with access to `user`
$scope.inputs = {
fullName: user.fullName,
email: user.email,
...
};
// html
<input ... ng-model="inputs[input.model]">
Since ng-model only accepts a reference, variations of this are essentially all you can reasonably do.

Related

Nested ng-repeat with model binding

HTML:
<div class="panel panel-default" ng-repeat="(section, sectionData) in report">
<div class="panel-heading">{{sectionData.text}}</div>
<div class="panel-body">
<div class="row" ng-repeat="(part, partData) in sectionData.attr">
<div class="col-md-2">
<label>{{partData.text}}</label>
</div>
<div class="col-md-10">
<div class="form-group">
<div class="radio-inline" ng-repeat="condition in radioValues">
<label class="radio-inline">
<input type="radio" name="{{section}}-{{part}}" ng-value="{{condition.value}}" ng-model="partData[model]">
{{condition.text}}
</label>
</div>
</div>
</div>
</div>
</div>
</div>
JS model:
$scope.radioValues = [{
text: 'Good',
value: '1'
}, {
text: 'Average',
value: '2'
}, {
text: 'Needs Improvement',
value: '3'
}];
$scope.report = {
card: {
text: 'Card',
attr: {
front: {
text: 'Front',
model: 'detail.report.card.front',
},
rear: {
text: 'Rear',
model: 'detail.report.card.front.rear'
},
assembly: {
text: 'Assembly',
model: 'detail.report.card.front.assembly'
}
}
} //, and a lot of others like card
};
// Instantiate the model so that values are preselected
for (var section in $scope.report) {
for (var part in $scope.report[section].attr) {
initModel($scope.report[section].attr[part]); // basically sets the model values defined in $scope.report to 1
}
}
The $scope.report object is used to create the html and I'm trying to set the value of ng-model in the html to strings defined in the $scope.report. Along with that, I'm also trying to set the default values of each set of radios.
Is the ng-model="partData[model]" part correct? After setting the model values in the controller, the radios aren't preselected when the page loads. The model defined in the $scope.report should bind to the $scope directly. E.g. detail.report.card.front.assembly should actually become $scope.detail.report...
How do I make this work? Is it the right use of angular? Better alternatives?
I was able to get this done using a directive with isolated scope.
Basically, I shifted the html to a template called report. I changed the template html a little bit. Here's the changed code:
<div class="radio-inline" ng-repeat="condition in radioValues">
<label class="radio-inline">
<input type="radio" name="{{section}}-{{part}}" ng-value="{{condition.value}}" ng-model="detail.report[section][part]">
{{condition.text}}
</label>
</div>
Then created a directive like so:
app.module('').directive('rating', function(){
return {
scope : {
report: "=",
detail: "=",
radios: "="
},
restrict : 'E',
templateUrl : '../view/rating.html',
link : function($scope, iElm, iAttrs, controller) {}
};
});
And in the html I simply call:
<rating report="report" radios="radios" detail="detail"></rating>
So I was able to access the detail object in the parent scope by passing it to the template. This allowed me to modify the parent scope's model directly.

Dynamically bind objects to inputs in angular

I have these objects right here that I will use to save data from a form, and later send it to an api as JSON :
$scope.price = {}
$scope.item = {"price":$scope.price, };
I also have these field which will be used to dynamically generate inputs on a html page:
$scope.fields = [
{
name: $scope.item.title,
title: 'Title',
type: {
view: 'input'
}
},
{
name: $scope.price.regular,
title: 'Regualar Price',
type: {
view: 'input'
}
}
];
Now in order to generate the form I use this code:
<div class="form-group" ng-repeat="field in fields">
<label>{{ field.title }}:</label>
<span ng-switch on="field.type.view">
<span ng-switch-when="input">
<input
ng-model=field.name
type="text"
/>
</span>
</span>
</div>
And with this code, it is not assigning the values in the input to the objects. Is there a way to do it? I know I can do it this way:
ng-model="item[field.name]"
But that limits me to only one level of the object. I want to be able to bind nested objects. And I just can't seem to figure it out. Thank You!

ng-repeat controller and parent update

I've been reading a lot on angular scopes and inheritance but I can't get my head around this problem. Here is the HTML I'm using:
<div class="sensorquery-sensor" ng-repeat="sensor in query.sensors" ng-controller="SensorsCtrl">
<select class="form-control"
ng-model="selected.sensor"
ng-options="sensor.name for sensor in parameters.sensors">
</select>
<select class="form-control"
ng-model="selected.definition"
ng-options="definition.value for definition in definitions">
</select>
<select class="form-control"
ng-model="selected.operation"
ng-options="operation for operation in operations">
</select>
</div>
As you can see, I have an ng-repeat based on query.sensors. The values stored in this query.sensors array should be simple:
{
name: 'sensor1',
type: 'temperature'
}
But I want to use a child controller: SensorsCtrl to handle more logic per sensor and hide the complexitiy of sensors. A sensor can look like:
{
name: 'sensor1',
attributes: [
'model',
'brand'
],
definitions: [
{
datatype: 'double',
value: 'temperature'
},
{
datatype: 'integer',
value: 'pressure'
},
{
datatype: 'string',
value: 'color'
}
]
}
So it's in my SensorsCtrl controller where I want to put the selection logic:
$scope.$watch('selected.sensor', function(sensor) {
$scope.definitions = sensor.template.definition;
});
$scope.$watch('selected.definition', function(definition) {
if (definition.datatype === 'string') {
$scope.operations = ['Count'];
} else {
$scope.operations = ['Max', 'Min'];
}
$scope.selected.operation = _.first($scope.operations);
});
How do I keep the link with the parent query.sensors[$index] while transforming the sensor as the user selects different sensors and definitions?
Setting up a watcher on selected and updating the query.sensors array triggers an infinite $digest loop.
I found the solution which was right before my eyes:
<div class="sensorquery-sensor" ng-repeat="sensor in query.sensors" ng-controller="SensorsCtrl">
<!-- ... -->
</div>
The sensor is a reference to the original object of the parent query.sensors. An it's created in the scope of the sub-controller.
So in my SensorsCtrl controller, I can just watch:
$scope.$watch('sensor.definition', function(definition) {
/* ... */
});
So I can put hide some complexity in this controller while maintaining a proper link to the original element.
It does not answer the question of maintaining a less complex object but it's a different question I guess.

AngularJS - Binding radio button selection to model inside ng-repeat

I have a data model persons which takes the following form:
personsInfo = {
name: Adam
dob: 31-FEB-1985
docs: [
{
docType: Drivers License,
number: 121212,
selected: false
id: 1
},
{
selected: true,
docType: None
},
{
docType: State ID,
number: 132345,
selected: false,
id: 2
}
]
}
In my markup I have defined the following to dynamically generate radio buttons.
<div ng-repeat="personDoc in personsInfo.docs">
<input type="radio" name="personDocs" ng-model="personDoc.selected" value=""/>
{{personDoc.docType}} <span ng-hide="personDoc.docType === 'None'">Number: {{personDoc.number}}</span>
</div>
I want to be able to check the documents which have selected as true on page load, and then depending on what the user selects save the selected flag in my personsInfo model.
My intent here is to send the personsInfo model back to another page.
If somebody could point me to a working fiddle it would be greatly appreciated!
Thanks!
You're almost there just missing the binding to show which document is selected. We'll add an object to the scope to represent the selected item, then bind the forms to that model.
JS
app.controller('...', function($scope) {
$scope.personInfo = { ... };
$scope.selectedDoc = {};
$scope.$watch('personInfo',function() {
$scope.selectedDoc = $scope.personInfo.docs[0];
});
});
HTML
<div ng-repeat='doc in personInfo.docs'>
<input type='radio' ng-model='selectedDoc' value='doc' /> {{doc.docType}}
</div>
<form>
<input type='text' ng-model='selectedDoc.number' />
...
</form>

Populate checkbox values with model data in Ember.js

I have an ember application which has a number of users. Each of these users can be associated with a number of subjects. So I have a subjects model:
App.Subjects = DS.Model.extend({
subject : DS.attr('string'),
});
App.Subject.FIXTURES = [{
id: 1,
name: 'Sales',
}, {
id: 2,
name: 'Marketing',
}
];
and a users model:
App.User = DS.Model.extend({
name : DS.attr(),
email : DS.attr(),
subjects : DS.hasMany('subject'),
});
App.User.FIXTURES = [{
id: 1,
name: 'Jane Smith',
email: 'janesmith#thesmiths.com',
subjects: ["1", "2"]
}, {
id: 2,
name: 'John Dorian',
email: 'jd#sacredheart.com',
subjects: ["1", "2"]
}
];
I am having trouble representing this 1:M relationship in my templates. I have an edit user template (which Im also using to create a user) in which you can select the user's subjects via checkboxes. However, I want these checkboxes to be driven by the data in my subjects model. Is this possible? I have found very little documentation online and am very new to ember development. Here is my template:
<script type = "text/x-handlebars" id = "user/edit">
<div class="input-group">
<div class="user-edit">
<h5>User name</h5>
{{input value=name}}
<h5>User email</h5>
{{input value=email}}
<h5>Subjects</h5>
{{input type="checkbox" value = "sales" name="sales" checked=sales}}
{{input type="checkbox" value = "support" name="support" checked=support}}
</div>
<button {{action "save"}}> Save </button>
</div>
</script>
EDIT: Here is my current userController.js
App.UserController = Ember.ObjectController.extend({
deleteMode: false,
actions: {
delete: function(){
this.toggleProperty('deleteMode');
},
cancelDelete: function(){
this.set('deleteMode', false);
},
confirmDelete: function(){
// this tells Ember-Data to delete the current user
this.get('model').deleteRecord();
this.get('model').save();
// and then go to the users route
this.transitionToRoute('users');
// set deleteMode back to false
this.set('deleteMode', false);
},
// the edit method remains the same
edit: function(){
this.transitionToRoute('user.edit');
}
}
});
what you need to do is change this line in your template:
{{#each subject in user.subject}}
{{subject.name}},
{{/each}}
for this:
{{#each subject in user.subjects}}
{{subject.name}},
{{/each}}
did you notice I changed subject for subjects ?
and, I would also recommend you to change this code in App.SubjectController:
selected: function() {
var user = this.get('content');
var subject = this.get('parentController.subjects');
return subject.contains(user);
}.property()
to this:
selected: function() {
var subject = this.get('content');
var userSubjects = this.get('parentController.subjects');
return userSubjects.contains(subject);
}.property()
that's a better representation of the data.

Categories

Resources