I use this code:
$scope.$watch('message', function()
{
// the code
});
Is there any way to fire change event of message manually, so the code will be executed?
Few options:
Use $scope.$apply() to run the digest loop which call all of the watch expressions
Put you inner watch code inside a function and call it manually
Change messages :)
Another option here is declaring the function separately and using $scope.watch with the pointer.
var watchFunction = function(){
// the code
}
$scope.$watch('message',watchFunction);
watchFunction();
Related
I'm trying to disable some input boxes while a loop is run and then enable it after it is finished. I would like to do this with angularjs. I set a scope variable to true before the loop starts and then to false when it completes.
When doing this, nothing is disabled during the loop. It's like it's not digesting the function until after the loop completes when it's set to false anyway.
I've tried using jquery as well and it reacted in the same way.
HTML
<input class="form-control" type="text" ng-model="lineToChange.QtyOrd" ng-disabled="disableLinePartial" />
JS
$scope.updateFreight = function (firstLineIndex) {
//jQuery method acts the same
//$("input[ng-disabled='disableLinePartial']").attr("disabled");
$scope.disableLinePartial = true;
angular.forEach($scope.data.SalesOrder.Lines, function (e, i) {
//great functions here
});
$scope.disableLinePartial = false;
};
Am I missing something with how JS parses? What's a better way to do this?
Angular update the HTML on a loop: digestion cycles they call it. The change you made on $scope is not reflected in HTML while the updateFreight() function is not yet returned.
You can:
1) first $scope.disableLinePartial = true
2)
$timeout(function() {
// do your loop here
$scope.disableLinePartial = false;
});
The $timeout will allow the $scope change to apply, and only do the loop after at least one digest cycle.
You may also want to read about $scope.$applyAsync() and $scope.$evalAsync()
see:
http://blog.bguiz.com/post/60397801810/digest-cycles-in-single-page-apps/
I am using AngularJS and angular-datatable library.
I need to invoke modal on click on row.
Here is my part of code:
function rowCallback(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
// Unbind first in order to avoid any duplicate handler (see https://github.com/l-lin/angular-datatables/issues/87)
$('td', nRow).unbind('click');
$('td', nRow).bind('click', function() {
console.log(aData.title);
$timeout(function(){
Modal.showModal({
template : 'views/Modal.html',
Data : aData
});
}, 0);
});
return nRow;
}
console.log function works fine any way, but invoking modal function works as expected only when it wrapped in timeout. So can someone explain why this happening? Why only first function works good? I will be grateful for any explanations.
The reason you need the $timeout, is because you're using a jQuery event with an angular function. This is a bad idea in general and is against the design principles of angular - use ng-click instead.
If you must mix jQuery and angular together, then make sure you do it properly by making angular aware of jQuery events so that it can trigger its digest cycle.
You can trigger a digest in a few ways but the easiest (and most obvious as to what you code is doing) is by using $scope.$apply:
$scope.$apply(function () {
Modal.showModal({
template : 'views/Modal.html',
Data : aData
});
});
The reason the $timeout works is because $timeout is an angular wrapper function that triggers a digest cycle as part of its implementation (it's actually very similar to $scope.$apply, but it's less obvious what it's doing / why it's needed when you review your code later, so I'd advise using $scope.$apply instead).
Further reading: ng-book.
There is no callback for when the browser rendering engine will complete rendering the page.
But rendering the page is handled by the event queue. By using the $timeout function you are assigning Modal.showModal to the end of the event queue - after page rendering methods which have already been queued.
Therefore Modal.showModal will be called after the page has been rendered and work correctly.
I would like to fire all $watch/$observe listeners even if watched/observed value didn't change. This way I could provide a "testing only" feature to refresh current page/view without user interaction. I've tried to call $apply/$digest but that didn't worked:
$timeout(function(){
$scope.$apply();
});
$timeout(function(){
$scope.$digest();
});
Is there any other way to do it?
Best Regards,
Executing $scope.$apply() will trigger digest cycle as it internally calls $digest, below is example of manual change.
number variable won't get bound as timeout brings it out of angulars scope.
setTimeout(function () {
$scope.number = Math.random();
});
however you can "force" it to show up by manually applying scope changes:
setInterval(function () {
$scope.$apply();
}, 100);
Demos:
No change / Change with manual updates
This will not trigger watchers though. From $digest implementation, it checks if value has changed since the last watch evaluation and will run callback only if it did.
if ((value = watch.get(current)) !== (last = watch.last) ... [rootScope.js]
Therefore you will need somehow change value of the last execution and it's possible to do via $$watchers object on the scope:
$scope.digest = function () {
setTimeout(function () {
angular.forEach($scope.$$watchers, function (w) {
w.last.value = Math.random();
});
$scope.$apply();
});
}
DEMO
How about to use the $emit function then capture that event with $on function?
Within an $emit() event function call, the event bubbles up from the child scope to the parent scope. All of the scopes above the scope that fires the event will receive notification about the event.
We use $emit() when we want to communicate changes of state from within our app to the rest of the application.
_.bind($scope.$emit, $scope, 'myCustomEvent');
then on the capture phase:
$scope.$on('myCustomEvent', function() {
// do something
});
In my javascript code ( which is too long , so i can`t put it here ), functions are calling more than once , like suppose :
$("#button").bind({ click : Call }); // bind the Call with button click event
function Call()
{
alert("This message shows me more than once when i clicked the button");
}
if this alert message shows me more than once it means function Call() is calling more than once. Can anybody guess or tell me what's going on in my code? (Please don't ask me for code)
Works for me: http://jsfiddle.net/aC8Bm/
I'm guessing that you are binding more than once somewhere.
Also, I'd recommend either returning false from the Call function, or stopping event propagation.
One more thing: avoid naming functions with an uppercase -- that's reserved for constructor functions by convention.
You're hooking the event handler to the button the number of times 'Call' is being called. Do you have this code in something like a template or partial file?
Instead of doing this inside any function:
$("#button").bind({ click : Call });
Place the following somewhere outside:
$("#button").live("click", Call);
It will bind once for all existing and ever added #button
I have a javascript function. In thi function i am calling a button event like below.
$("#btnSave").trigger("click");
My query is , Is there any way to keep the control here on this line until the saving is done?
I have some code written underneath this line and it is being overridden.
Any suggestions?
It would have helped if you've posted some code.
You can do it in 2 ways:
1.) Use polling. After the trigger call use a loop to check for a flag that you must set when the save is complete. A timeout is needed for saving CPU from intensive js processing.
2.) Put the code to be executed after the trigger call inside a function. Pass this function as a callback to the onClick function.
function onSaveClick(e) {
//do my save stuff
e.data.callback();
}
No. 2 is recommended.
//attach onclick event
$("#btnSave").click(onSaveClick);
//you onclick function
function onSaveClick(event, callback) {
//save data
callback();
}
//trigger
$("#btnSave").trigger("click", afterSave);
//after save stuff
function afterSave(){
//do more stuff
}
Use a callback.
Get the lines under the trigger line and pass to your save function as callback when the event has success.