Angularjs dynamic binding for ng-model - angularjs

Here is the Plunker that describe my problem with dynamic binding in Angularjs.
http://plnkr.co/edit/fGgtOZ5IrJVo9QasQALc?p=preview
Before using Angularjs, I am used to using the input name/value like the following to generate desirable data structure for back end processing
<input type="text" name="computer[details][][purchaseddate]" />
<input type="text" name="computer[details][][warrantyperiod]" />
With Angularjs ng-model, it is possible to bind a complex data structure like
<input type="text" ng-model="computer.parts[0].name" />
However it does not work with dynamic property like the following:
<input type="text" ng-model="computer.details[0].name" />
Angular keeps telling me that I am trying to set property 'name' to undefined 'details[0]', I am aware of that but are there any ways to get the same behavior with previous input's name/value where I can specify dynamic property without having to declare it first?
Thank you,

Binding to attributes that don't exist yet works. You can bind to a.b.c even if $scope.a does not exists. Angular creates the objects and attributes on-the-fly.
<input type="text" ng-model="a.b.c" />
But you are trying to bind to an array element that does not exist yet:
<input type="text" ng-model="a.b[0].c" />
Angular would have instantiate the array and then push an empty object in it and then assign it's name. Apparently this does not work.

I ran into the same situation and tried everything.
This is how I was able to get dynamic values inside 2 deep ng-repeat:
JS:
$scope.newContact = {
name: [],
phone: [],
email: [],
notes: []
};
$scope.saveNewContact = function (idx) {
console.log($scope.newContact.name[idx]);
};
HTML:
<input type="text" ng-model="newContact.name[$index]" />
<input type="text" ng-model="newContact.phone[$index]" />
<input type="text" ng-model="newContact.email[$index]" />
<input type="text" ng-model="newContact.notes[$index]" />
<button ng-click="saveNewContact($index)">Save</button>

Related

Angular Js 1.x to display all the ng-model names in controller. In the form has more than 100 inputs

In AngularJs 1.x want to print all the ng-Model names in controller. In my application form has more than 100 input fields. Then my application one of the part, I have to declare all the input names into server side even few variable value is empty. So if I get ng-model names easy way to declare the variables.
For Example :
<div controller="IndexController as form">
<form name="myform">
<input type="text" data-ng-model="form.name" name="name"/>
<input type="text" data-ng-model="form.email" name="email"/>
<input type="text" data-ng-model="form.mobile" name="mobile"/>
</form>
</div>
Ouput: name, email, modile
You're best wrapping your ng-model in a scope object.
For example:
<input type="text" data-ng-model="form.details.name" name="name"/>
<input type="text" data-ng-model="form.details.email" name="email"/>
<input type="text" data-ng-model="form.details.mobile" name="mobile"/>
A model is just an object with key:value properties.
You can use the Object.keys to get an array of all properties keys and iterate on them, like below..
var keys = Object.keys($scope.details);
for(var i = 0; i < keys.length; i++){
console.log(keys[i]);
}
Consider you form model is like this:
let form = {"email": "abc#xyz.com", "fname": "abc"};
You can make use of for ... in loop.
The for...in statement iterates over the enumerable properties of an
object. For each distinct property, statements can be executed.
for (let i in form) {
console.log(form[i]);
}
OUTPUT
abc#xyz.com
abc

Dynamic model with Array object in AngularJS

I am saving my data in below format
$scope.data = {
name:'abc',
Address:[{
Address1:'XXXX',
state:'XXXX',
County:'XXXX'
}]
}
<input type="text" class="form-control" name="Address1" ng-model="data.Address[0][Address1]">
<input type="text" class="form-control" name="state" ng-model="data.Address[1][State]">
<input type="text" class="form-control" name="County" ng-model="data.Address[2][County]">
While retrieving the data I am getting data in below format:
$scope.data = {
name:'abc',
Address:[{
state:'XXXX',
County:'XXXX'
}]
}
Where one of the array objects (Address1) is missing so I am unable to update the form model even if the data is available. Is there any workaround to solve the above issue?
Change your input model to index 0, because that's the array item you are targeting. After that change your reference to the . notation and not using brackets []. You can use the brackets, but make sure to make them strings, like data.Address[0]['Address1']. But it's not necessary here. Also:
<input type="text" name="Address1" ng-model="data.Address[0].Address1">
<input type="text" name="state" ng-model="data.Address[0].state">
<input type="text" name="County" ng-model="data.Address[0].County">
(removed class for simplicity)
(are you using state or State?)

Assigning AngularJS model inside ngRepeat

I would like to iterate over an array in AngularJS like this:
var languages = ['en', 'es', 'fr'];
To generate something like this:
<input type="text" ng-model="mymodel.en" placeholder="Name (EN)">
<input type="text" ng-model="mymodel.es" placeholder="Name (ES)">
<input type="text" ng-model="mymodel.fr" placeholder="Name (FR)">
I have tried this:
<div ng-repeat="language in languages">
<input type="text" ng-model="mymodel.{{language}}" placeholder="Name ({{language | uppercase}})">
</div>
But throws an error:
"Syntax Error: Token '{' is an unexpected token at column ..."
How should I perform this loop?
Use mymodel[language] instead of mymodel.{{language}}
<div ng-repeat="language in languages">
<input type="text" ng-model="mymodel[language]" placeholder="Name ({{language | uppercase}})">
</div>
plnkr
See the plnkr, and start typing in any of the input fields to see the model changes.
you cantry something like this,
<input type="text" ng-model="mymodel[language]" ...
You shouldn't use {{}} notation inside ng-model here you can refer to your property in the mymodel object.
But it seems that you are trying to get binding via model somehow for your inputs. It's not gonna work in your case because you need to init mg-model directives.
For catching changed in your model from dynamically generated you need to compile used directives using $compile service.
Here you can check out sample. I googled it but I've solved similar problem in similar way.

Have AngularJs update {{binding}} as the user types in input[email]

Angular only updates the model from an input[email] after the user has entered a valid email address. How can I add a {{binding}} somewhere on the page that will update with the email value as the user types -- even before the user has typed in a valid email address?
Here's what I've tried so far:
<div ng-app>
<div ng-controller="MyCtrl">
<form name="MyForm" novalidate>
Name: <input type="text" name="name" ng-model="contact.name" /><br/>
Name as you type: {{contact.name}}<br/>
Email: <input type="email" name="email" ng-model="contact.email" /><br/>
Email as you type: {{contact.email}} (doesn't work)<br/>
Also doesn't work: {{$document.forms.MyForm.elements.email.value}}
</form>
</div>
</div>
Controller:
function MyCtrl($scope) {
$scope.contact = {};
}
(fiddle)
The name updates in real-time like I want, but the email doesn't.
I'd like to leave the email validation enabled. I just need some way to bind the un-validated input[email] text, so it updates as the user types.
Update 2014/7/8
I'd like to add an explicit requirement that the type="email" remains unchanged. I do not want to change the semantics of the markup to workaround a limitation of the framework. If need be, I'd rather pull in a complementary dependency (such as jQuery) to shim in the needed functionality.
I'm not opposed to handling validation in the controller — as suggested by rageandqq and charlietfl — if it could be done easily. Looking around though, it looks like it could be tricky (given my requirements).
That is how angularjs works. If you use <input type="email" /> angular is not going to bind your input till input will be valid in this case value must be a proper e-mail address.
please read more here : https://github.com/angular/angular.js/issues/1426
The workaround I've come up with so far is to use jQuery to listen for the input change and update an object on $scope that I've called formRaw. It works. Still, I'm hoping someone will come along and show me a better way.
The updated example:
<div ng-app>
<div ng-controller="MyCtrl">
<form name="MyForm" novalidate>
Name: <input type="text" name="name" ng-model="contact.name" /><br/>
Name as you type: {{contact.name}}<br/>
Email: <input type="email" name="email" ng-model="contact.email" /><br/>
Email Model: {{contact.email}}<br/>
Email Form: {{formRaw.email}}
{{q}}
</form>
</div>
</div>
And controller:
function MyCtrl($scope) {
$scope.contact = {};
$scope.formRaw = {};
$('input[type=email]').on('keyup change', function () {
var input = $(this);
$scope.formRaw[input.attr('name')] = input.val();
$scope.$digest(); // FIXME: there's got to be a better way
});
}
(fiddle)
The type="email" attribute on your E-mail input is what is causing the DOM binding to mess up.
Changing it to type="text" works allows your {{contact.email}} to display correctly.
Edited JSFiddle.

Dynamic Attributes with AngularJS

In some cases I need to apply different attributes to a node based on properties in my model.
For example, in one case I need to add a 'required' tag and in another case not. I've been using ng-if with different branches to accomplish this but the cases are getting out of hand quickly.
<div ng-if="model.required">
<input class="form-control"
type="text"
required
ng-model="model" />
</div>
<div ng-if="!model.required">
// as different options arise,
// i have more forks for each attribute combo
<input class="form-control"
type="text"
ng-model="model" />
</div>
Is there a better way to dynamic apply attributes to nodes?
I have quickly created a directive that allows you specify attributes dynamically.
http://jsfiddle.net/HB7LU/1806/
I'm not sure if it will have the desired effect you are after in this simple form, but it might be a good starting point. You essentially use:
<div dyn-attrs="someModelArray"></div>
And set your model accordingly:
$scope.someModelArray = [
{ attr: 'myattribute', value: '' },
{ attr: 'anotherattribute', value: 'val' }
];
In this case it would be best to make use of ngRequired:
<input class="form-control" type="text" ng-required="model.required" />

Resources