I would like to know the better way of assigning model name for each form elements using Angular JS.
I can assign it using individual scope variables.
<input type="text" ng-model="firstName"/>
<input type="text" ng-model="lastName"/>
I can also assign it using singleton object.
<input type="text" ng-model="contact.firstName"/>
<input type="text" ng-model="contact.lastName"/>
Which is the better way of handling form data in terms of memory and execution time?
You should choose the second option, in order to avoid issue with scope inheritance, see the doc:
Scope inheritance is normally straightforward, and you often don't even need to know it is happening... until you try 2-way data binding (i.e., form elements, ng-model) to a primitive (e.g., number, string, boolean) defined on the parent scope from inside the child scope.
According to Miško Hevery, the creator of AngularJS:
Whenever you have ng-model there’s gotta be a dot in there somewhere.
If you don’t have a dot, you’re doing it wrong.
The question is why?
Because ng-switch, ng-repeat, etc. creates their own scopes.
For example, have a look at this plnkr
<form ng-submit='addName()'>
Name 1: <input type='text' ng-model='name'/>
<input type='submit' value="Submit"/>
</form>
<p ng-switch='true'>
Name 2: <input type='text' ng-switch-when="true" ng-model='name'/>
</p>
<p>
Name 3: <input type='text' ng-model='name'/>
</p>
Output:
When you type in the Name 1 text box, the value shows up immediately in all text boxes. This is as expected. The problem is that now when you type into the Name 2 text box, it value gets disconnected and the three box values are no longer in sync. This is because of the way that JavaScript’s prototypal inheritance works.
To avoid, we should use dot in ng-model. For example, have a look at this plnkr
<form ng-submit='addName()'>
Name 1: <input type='text' ng-model='contact.name'/>
<input type='submit' value="Submit"/>
</form>
<p ng-switch='true'>
Name 2: <input type='text' ng-switch-when="true" ng-model='contact.name'/>
</p>
<p>
Name 3: <input type='text' ng-model='contact.name'/>
</p>
Output:
Now the code works with all three text box always in sync.
Source:
AngularJS MTV Meetup: Best Practices (2012/12/11)
5 AngularJS Antipatterns & Pitfalls
Why ng-model value should contain a dot
Nested Scopes in AngularJS
AngularJS: dot in ng-model
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
Does my ng-model really need to have a dot to avoid child $scope problems?
AngularJS: If you are not using a .(dot) in your models you are doing it wrong?
Related
A weird thing is happening on my form or maybe i am not doing it right, let me explain to you by presenting my code.
i have defined a form object inside my component
form = {};
There is a button on each row with data that when you click it opens a modal widow and also passes the item as argument.
<a class="btn btn-warning" (click)="open(item)"><i class="glyphicon glyphicon-pencil"></i></a>
This is the method that fires and opens a modal window but also assign the item object to form object above:
open = (item: any) => {
this.inventoryEditModal.open(); //Opens a modal window
this.form = item; // the assignment
}
The item object is available on the view by printing it out like this:
{{ form | json }} // i can see all item properties
The modal window contains a form where user will edit the item, so basically the input form fields should get filled with item properties values but for some reason the third level is undefined and i don't understand why, let me show you an screenshot of the second level
<input type="text" class="form-control" [(ngModel)]="form.alarmSystem" name="wireless">
The third level gets undefined:
<input type="text" class="form-control" [(ngModel)]="form.alarmSystem.wireless" name="wireless">
This issue is happening only for the third level "object.object.property". I am only showing one input field but the form contains more than 8 fields they all have same issue.
Not sure what i am missing here, but logically it should work. Do you have see this issue happening here and there or experienced your self?
Thank you in advance.
I am not sure if it helps your case, but I was in a very similar situation.
What helped me out was using the "safe-navigation-operator".
I assume that what you need to do is just add the ? after form:
<input type="text" class="form-control" [(ngModel)]="form?.alarmSystem.wireless" name="wireless">
The docs can be found here: https://angular.io/docs/ts/latest/guide/template-syntax.html#!#safe-navigation-operator
There can be 3 possible solutions with Angular 5
Don't assign ngForm to the template variable of the form (in form HTML element)
Don't do this -
<form #newItem="ngForm" (ngSubmit)="saveItem(newItem.value);">
Instead, do this -
<form (ngSubmit)="saveItem();">
<input type="text" class="form-control" name="wireless [(ngModel)]="form.alarmSystem.wireless">
<submit type="submit">Save</submit>
</form>
By this, you will be able to assign a 3 level nested property to
[(ngModel)] without any elvis or safe navigation operator (?).
If you are assigning ngForm to the form template variable then [(ngModel)] will give undefined for a 3 level nested property even if it already has some value.
So, use the name attribute instead -
<form #newItem="ngForm" (ngSubmit)="saveItem(newItem.value);">
<input type="text" name="alarmSystem.wireless" ngModel class="form-control">
</form>
Now, in this case, the nested property alarmSystem.wireless assigned
to the name attribute will be bound 2-way using ngModel directive.
And you can easily access it in the Event emitter function.
And the last solution by using elvis operator (?) is -
Here, again we will not assign ngForm in the form template variable, although there will not be any error but it won't store the value entered in input correctly.
So, split 2-way data binding with [ngModel] and (ngModelChange) like this
<form (ngSubmit)="saveItem();">
<input type="text" name="wireless"
[ngModel]="form?.alarmSystem?.wireless"
(ngModelChange)="form.alarmSystem.wireless=$event" class="form-control">
</form>
Also you can refer to this answer - Correct use of Elvis operator in Angular2 for Dart component's view
But, I don't recommend this solution as it adds up a lot of code.
How can I require a field only if it's not disabled? This didn't work:
<form name="foo">
<input type="text" name="bar" ng-required="!foo.bar.disabled">
</form>
Note that I am disabling the field directly through pure javascript, not with ng-disabled. I have a directive that runs through the form enabling/disabling things.
The directive listens to $on messages, and depending on what is gets will run:
element.find(':input').prop('disabled', true);
The $on messages come from a different scope, so I can't directly reference it and do ng-disabled=.....
Use ng-disabled with a scope variable. Your directive can then enable/disable the input through this scope variable. If your directive inherits from another scope, please use an intermediate factory to manage the scope variable.
$scope.barDisabled = dataSharer.barDisabled;
In above example the dataSharer is a factory and barDisabled directs to singleton.
In your form:
<form name="foo">
<input type="text" name="bar" ng-required="!bartDisabled" ng-disabled="barDisabled">
</form>
I have the following code:
<div data-ng-controller="MainController">
<input class="amount" type="text" name="" value="" />
<input class="result" type="text" name="" value=""/>
</div>
I want to take a numerical value from $scope and add it to a number entered by a user in the input with class "amount" and display the result in the input with class "result". So, basically, the variable is defined in the MainController function as the following:
$scope.cost = 100;
I'm a bit confused as to what the best way is to do this, I see there are ng-value and ng-model directives at my disposal but I am having a hard time understanding which is the right one for this application (and how to properly use them).
Seems like your application is asking for an inputs and they are going to submit there values OR gonna store it somewhere in DB. So ng-model (two way binding) will suits you application, which will update the value on model & view both.
Markup
<div data-ng-controller="MainController">
<input class="amount" type="text" ng-model="cost"/>
</div>
Above field will pre-populated as 100 and as you update it will also change $scope.cost value and the value if it is displayed on view anywhere.
Don't think about the ng-value that is only one way sort of binding. You can assign the value to input using ng-value="cost" that will only update the value attribute of input but when you update input from html you will never get those changes reflected inside cost scope variable as ng-value is meant for single way binding. Thinks like you should use use ng-value only when you want to display a value.
you should use ng-model
ng-value : Its a directive useful for evaluating expression and the value is bound to $scope used for evaluating expressions
ng-model : helps in two-way data binding ,view-->controller and vice versa moreover its a directive binds the value of HTML controls
Does Angular Material Design require an input ng-model to be equal to a variable in order for required to work?
Without using Material Design, the following error checking works perfectly fine.
<label>First Name (as it appears on your card)</label>
<input type="text" name="firstName" data-ng-model="test" required/>
Using Material Design though, the following always returns invalid unless the user types something, deletes it, and types something else.
<md-input-container>
<label>First Name (as it appears on your card)</label>
<input type="text" name="firstName" data-ng-model="test" required/>
</md-input-container>
However, I set test equal to something in the scope, then error checking works fine:
$scope.test = 'this value';
Is there a way to error check using Material Design without needing to specify a default value for fields?
I think you might not have initialized the ng-model variable in the controller.
Try initializing the variable,
$scope.test = '';
Edit: This question is no longer relevant as of Angular version: 1.3.0-beta.12 you can now parse ng-minlength and ng-maxlength dynamic values. See: https://github.com/angular/angular.js/issues/5319
My problem is quite simple: I need to dynamically create input validation (ex. ng-minlength) using interpolation.
And doing that I am running into some issues specifically generating the validation attributes for ng-minlength and ng-maxlength. I assume this is due to them only taking constants?
Below you can see my code, the reason I am using a wrapper through outerForm is that I cannot dynamically generate the name attribute of input elements using interpolation, and that I have to wrap each set of repeated inputs in an ngForm directive and nest these in an outer form element.
So again, the problem lies in the attribute ng-minlength="field.ValidationAttributes['data-val-length-min']" not being properly set.
When I print the value directly using {{field.ValidationAttributes['data-val-length-min']}} the value appears correct.
Do I have to create a directive to parse my information, do I need to create my own min/max validation or am I simply running into a syntax error?
<form name="outerForm">
<div ng-repeat="field in logEntry.StringValues">
<ng-form name="innerForm">
<input type="text" name="foo" ng-model="item.foo" ng-minlength="field.ValidationAttributes['data-val-length-min']" required/>
<span ng-show="innerForm.foo.$error.required">required</span>
<span ng-show="innerForm.foo.$error.minlength">to short</span>
</ng-form>
</div>
</form>
Hi you can use double {} to interpolate dynamic validation rules please see here: http://jsbin.com/xayiro/1/
If you can post you field.ValidationAttributes model I can update jsbin.
HTML:
<ng-form name="innerForm">
<input type="text" name="foo" ng-model="item.foo" ng-minlength="{{validation.minlength}}" required/>
<span ng-show="innerForm.foo.$error.required">required</span>
<span ng-show="innerForm.foo.$error.minlength">to short</span>
</ng-form>
JS:
$scope.validation= {
maxlength:20,
minlength:3
};