Markup
<div ng-app>
<div ng-controller="myCtrl">
<select ng-options="i for i in [1,2,3]"></select>
</div>
</div>
With this markup, options are not populated in select. When i provide ng-model along with ng-options it works as expected.
Why ng-model is required for the ng-options to populate the options?
ngOptions needs model in order to determine which option should be selected by default or which model to write selected object/value when selection changes.
If there was no ngModel directive, it would be difficult to access selected value, and it potentially lead to bad-practice code when people either query DOM to determine the value or write their own directives for this purpose. In both cases this is not ideal as this type of things is the key idea of Angular form elements directives.
Also don't forget that ngOptions in conjunction with ngModel allow developer to bind entire objects as the "value" of select elements, which would be tricky without ngModel.
Finally, if for some reason one doesn't want to have any model on select (although it makes little sense), it's possible to render options with ngRepeat.
If there is no model bound to the select, after choosing an option where would the selection be written out to?
As for the reason why the options are not displayed you can see the source code:
https://github.com/angular/angular.js/blob/master/src/ng/directive/ngOptions.js#L355
return {
restrict: 'A',
terminal: true,
require: ['select', '?ngModel'],
link: function(scope, selectElement, attr, ctrls) {
// if ngModel is not defined, we don't need to do anything
var ngModelCtrl = ctrls[1];
if (!ngModelCtrl) return;
The link function short cuts out and all the render functions are not created.
From the docs:
ngOptions should be used when the model needs to be bound to a non-string value
The very point of ngOptions is to provide values for the model, not to merely render option elements. Therefore it doesn't make sense to be used without ngModel.
Related
In a controller, we can sometimes access inputs values by the value of their DOM id instead of setting an ng-model directive and then binding the DOM value to $scope.
For example, in
<input type="text" ng-model="foo" id=foo>
we can either use $scope.foo or foo.value in the controller. What is the advantage of using $scope in this case?
I think that the main benefits of using ng-model instead of getting the value of input by id is two-way binding. Your variable from ng-model is always up to date and you can use it directly in html or wherever you want.
<input type="text" ng-model="foo" id="fooInput" />
<p>ng-model value: <span ng-bind="foo"></span></p>
If you choose approach when you get value from input by id you will lose this feature, but you get a little bit better performance. Because whenever you type into into, it will trigger a $digest cycle causing Angular to update all watchers and bindings in the app to see if anything has changed.
A little demo on plunker.
I'm trying to have some code run during the link callback of the ngModel directive using AngularJS on a select field that uses ngOptions.
module.directive("ngModel",function(){
console.log('ng-model called');
return {
restrict: 'A',
priority: -1, // give it lower priority than built-in ng-model
link: function(scope, element, attr) {
console.log('watching');
scope.$watch(attr.ngModel,function(value){
if (value){
console.log("changing");
}
});
}
}
});
See this fiddle which demonstrates the problem:
http://jsfiddle.net/d3r3zwLj/3/
The first select field is populated using ng-options, while the second has its options explicitly written out in html. If you open up the console, you can see that you only see the "changing" message when you change the second select field. Changing the first does nothing.
You'll also notice immediately that you only see 'ng-model called' and 'watching' once, even though there are two fields with ng-model on them.
I'd expect ngModel directive to work on both select fields. What is ng-options doing that is preventing the ngModel from working?
Thanks!
Looking at the doc for ng-options:
https://docs.angularjs.org/api/ng/directive/ngOptions
"Directive Info This directive executes at priority level 0."
If you change the priority of the directive to 0, it runs successfully. I'm not sure what all the implications are there, but that's why it was happening.
When you use the ng-options directive, it has another optional ng-model directive, which actually sets the default value to be shown from the options. So in your case, the second list does not have a ng-options directive which makes ng-model look like a regular one. Maybe you can just change the name of your directive.
This is a bad way to update functionality of built in directive, decorators are there for this purpose. Check the documentation
I've been trying to figure out a way to trigger the validation routines on an input element when a button is clicked in the same form. I've been looking at a few different ways of doing this. What seems to be the least convoluted is to create a directive that modifies an input button to fire the $validate method on the target form element. I've set this up without too much trouble but I've gotten blocked at how to modify the ngClick event handler so that it triggers the $validate while leaving the original HTML-defined ngClick intact.
I was attempting to use the directive template function to extract the original ngClick method and chain it to the new ngClick function defined in the directive. This started to turn into a mess quite quickly and I'm concerned about how brittle it might be.
Is there a way to intercept the ngClick handler in a directive and to still have the original functionality intact?
Alternately, I'm open to suggestions about how to fire the validation routines on the input field when the button is clicked with minimal involvement of the controller layer.
This is a classical example of an XY-question (if not a double-XY-question).
You don't need to "chain event handlers" (whatever you mean by that). Neither do you need to, I think, trigger the validation manually just because you are validating against external data.
Validation in Angular just runs - and it is not meant to be triggered other than by changing the data.
To add your own custom validator you need to create a directive (which it seems like you did). In that directive you probably need to specify what you are validating against, like an array of strings against which you want to check for duplicates.
Let's say, for simplicity, that you want to validate against another value in the ViewModel. Suppose, this how it would be used:
<input ng-model="bar">
<form name="form1">
<input ng-model="foo" not-equal-to="bar">
</form>
<span ng-show="form1.$error.notEqualTo">error: foo is equal to bar</span>
So, you need to create a directive notEqualTo that adds a validator to the ngModel.$validators pipeline. This directive also needs to $watch for changes to bar and re-set the validity:
app.directive("notEqualTo", function(){
return {
require: "ngModel",
scope: {
notEqualTo: "="
},
link: function(scope, element, attrs, ngModel){
// register "notEqualTo" validator
ngModel.$validators.notEqualTo = function(modelValue){
return validate(modelValue, scope.notEqualTo);
};
// rerun validation on changes to scope.notEqualTo
scope.$watch("notEqualTo", function(){
ngModel.$setValidity("notEqualTo",
validate(ngModel.$modelValue, scope.notEqualTo));
});
function validate(one, other){
return one !== other;
}
}
};
});
plunker
Is there any performance improvement in using ng-change in an input instead of ng-model?
I pressume that when ng-model is used in an input, then a "$watch" (or similar) is made by angular in a variable, and that adds work load.
But if ng-change is used, then the variable (model) can be updated when needed, code can be executed only when this variable is changed by the input.
This works assuming that only one input can change a variable.
Example follows:
using ng-model
<input type="text" ng-model="ElTexto">
<div ng-show="ElTexto"></div>
using ng-change
html
<input type="text" ng-change="elTexto()">
<div ng-show="ElTexto"></div>
js
$scope.elTexto(){
$scope.ElTexto = true;
}
ng-change requires ng-model, so you can't choose between the two. You must use ng-model, and can also use ng-change if you wish.
Be aware that the two are VERY different. ng-model will keep your input's value and its backing model in perfect sync; ng-change will indicate that the user is interacting with the input. If you care about the value they're changing, like if you're doing autocomplete, just use ng-model and have all your code share the same variable. If you specifically want to take an action when the input changes, regardless of what the value is, then you can use ng-change for that.
ng-change will have batter performance then ng-model. As in every digest cycle ng-model will be evaluated while ng-change will be evaluated on change of input.
I am new to AngularJS, I successfully designed the repeated forms using nested ng-repeat. But I can't find the right way to get all values corresponding to the forms.
Here is my updated JSFiddle: http://jsfiddle.net/MrSuS/gTc5v/7/
Update: And you can see, radio input is also not working properly.
there is no binding in your application use ng-model to bind your field values.
if you want to design custom form depends on your dynamic data you should write a directive like this Example Form Directive
UPDATE
I think best way is repeat html form in your position.
It is simple, easy and less code...
<div ng-repeat="form in forms">
<h2>{{form.name}}</h2>
<input type="text" ng-model="form.answer.city"><br/>
...
here is JSFIDDLE example...
Firstly use ng-model for binding. Second, use $index as array subscript for your ng-model
ng-model="input[$index]"