Fire ng-change when ng-model updated programmatically inside ng-repeat - javascript

I read topics related to this and found following, but still I am stuck.
How to $watch changes on models created by ng-repeat?
I am trying to implement plus, minus counter with following code. Now whenever ng-model updates either by clicking +/- button I want to fire ng-change. I understand that ng-change doesn't fire when the ng-model updated programatically. But the refrenced Stackoverflow has solution for that to add $watch on the ng-model. But its working if I create separate controller, not working inside current controller. ng-change is calling functions inside current controller. How to fix it??
<div class="input-group" ng-repeat="product in oc.itemdetail.lines">
<input type="button" value="-" class="minus"
ng-click="product.line.total = product.line.total - product.stepCount">
<input type="number" ng-if="condition 1" ng-model="product.line.total" min="" max=""
step="product.stepCount" oninput="some condition"
ng-change="oc.function1()" />
<input type="number" ng-if="condition 2" ng-model="product.line.total" min="" max=""
step="product.stepCount" oninput="some condition"
ng-change="oc.function2()" />
<input type="button" value="+" class="plus"
ng-click="product.line.total = product.line.total + product.stepCount">
</div>
I have two input box above, based on ng-if condition either one will be shown at a time. Each ng-change is calling different function inside current controller. If I put separate controller then on click of +/- button following function is firing. But I want to call function inside ng-change
$scope.$watch('Count', function (oldValue, newValue) {
if (newValue != oldValue)
console.log(oldValue, newValue);
});

The code should avoid using the onchange attribute with the ng-model directive. The ng-if directive uses alot of resources. If the only reason it is being used is to switch the ng-change function, it should be avoided. The choice of ng-change function can be made in the controller.
<div class="input-group" ng-repeat="product in oc.itemdetail.lines">
<input type="button" value="-" class="minus"
ng-click="oc.decrement(product)">
<input type="number" ng-model="product.line.total" min="" max=""
step="product.stepCount" ng-change="oc.update(product)" />
<input type="button" value="+" class="plus"
ng-click="oc.increment(product)">
</div>
Avoid complex formulations in templates. Instead put them in the controller:
oc.update = function(product) {
if (oc.<condition 1>) {
oc.function1();
};
if (oc.<condition 2>) {
oc.function2();
};
};
For performance reasons, avoid using watchers. Instead use the functions that change the model to invoke update operations:
oc.decrement = function(product) {
product.line.total = product.line.total - product.stepCount;
oc.update(product);
};
oc.increment = function(product) {
product.line.total = product.line.total + product.stepCount;
oc.update(product);
};
Putting complex expressions in the controller makes the code easier to understand, debug, test, and maintain.

You can try by moving this 'Count = Count + s.increment' code on the ng-click event into a function in the JS file and in that function you can call ct.function2().
eg:-
$ct.Counter = function(){
Count = Count + s.increment;
ct.function2();
}
and call this method on ng-click
ng-click="ct.Counter()"
Similarly you can implement the minus scenario.

Related

NgModel call onchange function

I hava this type of code:
<div ng-repeat="point in points">
<input type="text" ng-model="point.oy" onchange="angular.element(this).scope().changeLocation(point.name)">
<input type="text" ng-model="point.ox" onchange="angular.element(this).scope().changeLocation(point.name)">
<!--.... other inputs -->
</div>
What should I do to make the onchange function not run on the first bind on ng-model.
It means that function changeLocation() should run only if user change text input.
What you can do is bind a watcher to your scope variable point in order to listen for user changes after the initialization of point. ex.
$scope.$watchCollection('point' , function(newPoint , oldPoint){
//something
});

How to change one-time binding data in AngularJS?

I have a div which show details like mobilenumber, name etc. like {{::mobilenumber}}, {{::name}}
In that div, there is a button that renders the same values in the new form
By using the button in the form, the user can change the values but in the div where I am showing details, values don't change after clicking on the button
<form ng-submit="form.$valid && saveDetails()">
<input type="text" class="form-control capitalize" placeholder="Full Name" name="fullname"ng-model="address.fullname" maxlength="50" ng-trim="true" autocomplete="off" required >
<span><!-- Mobile Number required --></span>
<input type="text" class="form-control capitalize" placeholder="Mobile Number" name="mobilenumber" id="mobilenumber" ng-model="address.mobilenumber" ng-minlength="10" maxlength="12" ng-trim="true" autocomplete="off" required>
<span><!-- Mobile Number required --></span>
<button ng-click="form.submitted=true><span>Update User Details</span</button>
</form>
Do I want to use one-way binding only?
I tried using $scope.$broadcast('$$rebind:refresh'); but still values don't change.
Any help or guidance would be very helpful for me.
If you really want to keep some sort of one-way-binding...
What you could do, is just use two way binding but with a dataset in between. It gives some overhead but it is a possible solution to your problem. In order to update the view, you just update the copied data. You can control when the data in the view is updated.
When you use interpolation {{mobilenumber}} in your html, angular creates a watcher that watches the property mobilenumber on a scope:
$scope.$watch('mobilenumber', function() {
// update DOM
});
Whenever the value changes, DOM is updated.
However, if you use one time binding {{:mobilenumber}}, as soon as your callback receives truthy value, angular removes the watcher:
var unwatch = $scope.$watch('mobilenumber', function() {
if (value) {
// update DOM
unwatch();
}
);
And since there is no more watcher for mobilenumber, whenever you update values on the scope inside your saveDetails() method, the callback is not triggered and DOM is not updated.
If you're planning on updating values constantly, you should not use one time binding. Use regular bindings:
<div>{{mobilenumber}}</div>

Update DOM only when $scope data changes

In my angular js app, I noticed that the DOM updates any time I call a function. This happens even when the function did not change any $scope variable.
I'm using an ng-repeat to create a set of checkboxes as shown below.
HTML
<a ng-click="someFunction()" >Some Function</a>
<form action="/settings/save">
<label>
<input ng-repeat="option in settings.active" name="options[]" value="{{option}}" checked="checked" />
{{option}}
</label>
<input type="submit" value="Save" />
</form>
JS
angular.module("myapp")
.controller("settingsCtrl", function($scope, $loadServ){
//$loadServ is a service for fetching data from the server
$loadServ("/settings/load")
.success(function(response){$scope.settings = response.data});
$scope.someVariable = "something";
$scope.someFunction = function(){
//There's nothing here yet
}
//More code follows
})
I noticed that all the unchecked checkboxes are checked when the "Some Function" button is clicked. I inspected the DOM and realised that all the checkboxes were re-rendered when the button was clicked.
Is there a way to update the DOM only when the $scope changes?
Note: I can't use one way binding because the $scope.settings.active can be changed by some other function
I've found the source of the error. It was caused by a filter that was applied far above the nodes

JQuery selecting radio button using a variable

I'm trying to select a radio button using a variable but, although I can print the selected value the button does not stay selected.
This button is defined in an angular template as follows:
<a ng-click="selectNode($event, node)">
<input type="radio" name="library" style="float:left;" id="id-{{n}}" />
</a>
Where id is a GUID so is definitely unique.
Then, because it is the angular click event that is called when a button is selected I call this code in selectNode:
context.selectedNodes = [node];
$scope.selectedNode = node.$model.name;
var id = '#id-' + node.$model.id;
//console.log(typeof id);
//console.log(id);
$(id).prop("checked", true);
alert($("[name=library]:checked").val())
Which should theoretically check the radio button. However, it checks for a moment (it is checked when I call the alert) and then seems to disappear. I am however able to hardcode in an id and it stays checked.
I recommend diving more into the tools angular gives you to handle this things simply. If you need to track the value on this input, tie it to a model. If you want to process something once the checkbox has changed, use ng-change and tie it to a function.
<input type="radio" name="library" style="float:left;" ng-model=libraryModel ng-change="doSomething()" />
Keep in mind that doSomething() needs to be in scope, so in your controller, you need to define the function as $scope.doSomething(). Your model will also be attached to the $scope object, so you'd reference it as $scope.libraryModel. You can initialize the model as true or false as needed for a default value in the controller, then any user changes will auto update this value.
You're mixing jQuery and Angularjs, and it is not really worth. You can do the following just by using AngularJS ngModel, if you use AngularJs in your project.
Controller
function Controller($scope) {
//Init data input to value 1
$scope.data = ['1'];
}
HTML
<input type="radio" name="name" value="1" ng-model="data">
<input type="radio" name="name" value="2" ng-model="data">
Here, our $scope.data is set to 1 in our Controller, so it will match with the first input.

Angular.js: update binding after manual modification

I'm only starting to dive into angular.js and have found this issue that I can't seem to get around. Consider this simple code:
<input type="text" ng-model="test">
<input type="text" value="{{test}}">
When I write in the first field, the second one is updated nicely. When I write in the second field and then go back to the first one, the binding is not updated anymore. Interestingly though, the HTML attribute value does get updated - it's just not displayed.
Equivalent (at least roughly) code in vanilla javascript does not suffer from this:
<input type="text" id="model">
<input type="text" id="binding">
<script>
var model = document.getElementById("model");
var binding = document.getElementById("binding");
model.addEventListener("keyup",function() {
binding.value = model.value;
});
</script>
Here's a fiddle for you to test both: http://jsfiddle.net/Q6b5k/
Any idea why this happens when using angular.js and how to fix this?
[EDIT] Judging by the initial replies, it appears I have not made it clear. I do not want the second field to update the first one. The binding is to be one-way only, e.g. to allow filtering or even manual corrections (such as automatic creation of a URL alias in a blog post creation form). http://jsfiddle.net/Q6b5k/1/
The value attribute is only used when rendering the initial HTML. After the page load, everything else happens in the Angular Event Loop and therefore you need to do something that event loop can pick up. You can use ng-change for what you are looking to do:
<input type="text" ng-model="test" ng-change="test2=test.toLowerCase();" />
<input type="text" ng-model="test2"">
This happens because {{value}} does not create a binding, it is used for interpolation.
The simplest solution is to use ng-model in both the fields
<div ng-app>
Angular.js:<br>
<input type="text" ng-model="test">
<input type="text" ng-model="test">
</div>
Demo: Fiddle

Categories