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.
Related
I set the input value Array property sum and it shows value in input but when submitting form does not get Quantity property in Order object. If I change the value then I get Quantity property value. How can I get model value from ng-value?
<input ng-model="Order.Quantity" ng-value="subOrderList.sum('Quantity')" type="number">
To answer your question, "ng-value does not update Ng-model", it is by design. As mentioned in comments, ng-value and ng-model are not intended to by used in this way.
It isn't entirely clear what you are trying to achieve here, so here's a couple potential solutions:
If you are just looking to display a value then you don't need to use an input at all. Both of these will behave the same and update when needed:
<span>{{subOrderList.sum('Quantity')}}</span>
<span ng-bind="subOrderList.sum('Quantity')"></span>
If you actually need this value to be updated by user input then the HTML would look like this:
<input ng-model="Order.Quantity" type="number">
And then you will need to manually update that value in a controller or service when needed:
Order.Quantity = subOrderList.sum('Quantity');
From your comments it almost seems like you need an input that also changes dynamically and sporadically, but without a data example or more code I can't really see how that would work.
Good evening,
I am writing an application using AngularJS and I require for the application to send data with a POST request to the nodejs server.
My data is structured like as a json object and it has data binding thanks to the AngularJS framework.
As of now, a function is dynamically trying to create possible values that the user might like inside of some input tags. An example:
<button ng-click="generateFoodAndBeverages(row)>Generate</button>
<input type="text" ng-model="row.service.day.beverage" placeholder="beverage" />
<input type="text" ng-model="row.service.day.food" placeholder="food" />
The two input values can be set by the user by typing in the value they would like (e.g. "Cola", "Hamburger"), but above the input tags is a button that can generate the input values for the user.
The function that generates the values takes them from an array and then at the end of the function returns two possible values, one for beverages and one for food.
When it has the two returning values it changes the attribute value of both inputs, setting them to the two possibilities generated by the function:
jQuery("#input1").attr("value", generateFoodAndBeverages(row)[0]);
jQuery("#input2").attr("value", generateFoodAndBeverages(row)[1]);
This is not perfect nor elegant but it's working. The function populates and dynamically changes the value attribute of those two input elements each time the user requests for automatic generation of food and beverages so the values are actually set and do exist.
Even so, even if I see them on screen as text inside the input fields, my POST request does not recognize the fact that the ng-model actually changed. The only way the ng-model registers the changes to the value attribute of the input fields is if the user types something with his keyboard, manually changing the value attribute. Another example:
<input type="text" value="generateValue()" ng-model="row.service.info" />
The one up here does not change the ng-model value at all.
<input type="text" value="User Typed Value" ng-model="row.service.info" />
This other one instead does change the ng-model value and as it changes and exists, it is passed to the $scope that can later be sent as a POST request to the server.
Any ideas as to why the "automatically and dynamically generated" value of the input field does not get registered by the ng-model while the user typed value does?
Thanks in advance!
[EDIT]
Apparently the problem comes with the ng-model not changing. I tried to debug the problem by applying an ng-change in the input. If the change is done by javascript, it is not registered with the ng-model and the ng-change function does not fire because the ng-model was not changed even tho' I can clearly see the new value set by javascript for the input tag. If I change the value of the input tag by hand the ng-change is fired and the console logs the change.
I could apply the changes directly to the ng-model if it weren't so different for each row.
Having the ng-model like this:
<input ng-model="row.serviceInfo.DayObject[dayString].food" />
<input ng-model="row.serviceInfo.DayObject[dayString].beverage" />
How would I be able to apply the changes directly to the ng-model given how dynamic the model is. As an example, I could have 1000 rows, each with their own serviceInfo object. I don't know how I could change the model for each of those rows with the dynamically generated values.
[EDIT]
The problem was indeed with ng-model not changing. The solution consisted in applying the changes to the ng-model for each element inside the dynamically generated values function. Thanks everyone for the input. I'll leave this piece of code here if anyone ever comes across the same problem! Thanks again!
let foodEl = angular.element(the row element food input);
let beverageEl = angular.element(the row element beverage input);
$scope.displayedCollection[i].serviceInfo = {
"day" : {
"food" : generatedValuesFood(el, day),
"beverage" : generatedValuesBeverage(el, day)
}
};
foodEl.val($scope.displayedCollection[i].serviceInfo.day.food);
beverageEl.val($scope.displayedCollection[i].serviceInfo.day.beverage);
I think that your problem is quite simple. As #ssougnez said, don't mixed jquery with angularjs. Angularjs use data-binding concept, don't use jquery style to change the input value instead use the ng-model directive to bind data from the model to the view on HTML controls (input, select, textarea). In your generateFoodAndBeverages function just set the ng-model value according to which row for eg:
var generateFoodAndBeverages = function () {
$scope.row.service.day.beverage = array[0];
$scope.row.service.day.food = array[1];
};
I'm developing the AngularJS client. I've got a custom directive used as an attribute. The directive checks the access level of the element and sets it to be disabled if the current user is not allowed to use it.
The problem begins when the same element has ng-disabled attribute. In this case the ng-disabled sets the ability of the element, never mind of what I set in my custom directive.
For example I have a button that should be disabled in case the form is invalid. At the same time I'd like to use my custom directive in order to set the button to be disabled if the user doesn't have a permition to use it.
<button ng-disabled="myFrm.myCtrl.$invalid" my-custom-directive="controlName"/>
Inside myCustomDirective I check if the named control is allowed to be activated by the user. If not - I set the disabled attribute to the element. But in case myFrm.myCtrl.$invalid is false ng-disabled removes the disabled attribute and the button is enabled.
Is there any solution to this problem? How can I prevent from ng-disabled to perform its operation?
Does your example directive reflect how you applied your actual directive to the button element? I noticed that your example directive is not following the correct naming convention of making each upper case letter in the directive name a lower case letter with a leading hyphen. i.e. myCustomDirective should be applied to the button like so:
<button ng-disabled="myFrm.myCtrl.$invalid" my-custom-directive="controlName"/>
Otherwise your directive will not be complied or linked for that button.
The only other thing I could think of without seeing the actual code is the priority of the directive. According to the angular docs for the ngDisabled directive:
This directive executes at priority level 100.
By default custom directives have a priority of 0. As long as you have not changed this directive parameter your directive should be compiled after ng-disabled and linked after ng-disabled and therefore have the final say on whether or not the button is disabled or enabled.
-- EDIT --
You should add a watch to myFrm.myCtrl.$invalid as was suggested by another and reapply your directives rules whenever the value changes. You don't need to pass the whole controller into your directive though, you could simply use two way binding on myFrm.myCtrl.$invalid. I am not sure how $watch priority works yet. I am hoping that because your directive will be compiled first it will apply its watch on myFrm.myCtrl.$invalid after ngDisabled does and hopefully that means it will handle value changes of myFrm.myCtrl.$invalid after ngDisable does so that your directive has the final say on what rule is applied.
Finaly I've found a solution to my problem. Instead of watching ng-disabled variable I've totaly diconnected the ng-disabled from its variable. In order to do it I've set the ng-disabled to be allways true in my own directive. My directive is an attribute, so after I've tried some different ways to do it, the solution was to add in my directive constructor the following code:
this.isDisabled = "true";
this.attrs["ngDisabl​ed"] = this.isDisabled;
It's very very important to set the this.isDisabled to "true" as a string and not boolean. Otherwise it doesn't work.
I have a checkbox in my view
<input type="checkbox" ng-model="trackers[tracker._id].enable" ng-click="toggleTracker(tracker._id);"/>
And a function in my controller
$scope.toggleTracker = function(trackerId){
$scope.trackers[trackerId].enable = !$scope.trackers[trackerId].enable;
console.log($scope.trackers[trackerId].enable)
}
But each time I check the box the enable property does not change. What could be wrong with my code?
Since you have ng-model connected to the input it should change when you click. Then you also have the ng-click so it changes back to the first value.
Just remove the ng-click and your good.
You shouldn't use both ng-model and an ng-click function toggling the enable state. Maybe it overrides and negate the toggle because they are executed one after the other.
Just use the ng-model property and it should work.
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.