ExtJS setTimeout loop function not working (losing scope) Ext.bind - extjs

I have a ExtJS 4.2.1 Controller where I fires a function after 1 second using setTimeout:
onPrint: function () {
var me = this;
// start some stuff here...
// end some stuff here...
// wait 1 second and call checkDownloadComplete function
setTimeout(me.checkDownloadComplete, 1000);
},
checkDownloadComplete: function () {
var me = this;
// validate stuff here...
if (something == "true") {
return;
}
// first approach but didn't work (maybe because the scope)
setTimeout(me.checkDownloadComplete, 1000);
// sencond approach but didn't work
Ext.bind(function () {
setTimeout(checkDownloadComplete, 1000)
}, me)
},
My first try was to use:
setTimeout(me.checkDownloadComplete,1000); But this didn't work
My second try was to comment the last line, and use Ext.bind:
Ext.bind(funciton(){setTimeout(checkDownloadComplete,1000)},me);
Any clue what I'm doing wrong? Because none of those work to call again a function it self.
Thanks
UPDATE:
I also try this but without success:
setTimeout(Ext.bind(checkDownloadComplete,me), 1000);

The solution was to change both setTimeout calls to:
setTimeout(Ext.bind(me.checkDownloadComplete, me), 200);
The problem was that on the first call of the setTimeout, the checkDownloadComplete scope was changed to a setTimeout scope instead of controller scope, so changing both fixed the problem-

Related

AngularJS Share Data Between Controllers Using Service And Watch For Updates

Simple task here, but not sure about the mistake.
My service:
app.factory('Progress', function () {
var data = {
progressPercentageLoaded: 0
};
return {
getProgress: function () {
return data.progressPercentageLoaded;
},
setProgress: function (progress) {
data.progressPercentageLoaded = progress;
}
};
});
I have one controller that is uploading a file, this one sets the progress value.
//in my controller
$scope.progressPercentageLoaded = {progress:0};
//a few lines down
function (evt) {
console.log(evt);
$scope.progressPercentageLoaded.progress = evt.loaded;
Progress.setProgress($scope.progressPercentageLoaded.progress);
My second controller should simply watch the service for changes and update the view, but it stays stuck at zero even though I confirm the upload is happening and that evt.loaded is changing.
$scope.progress = 0;
$scope.$watch(function () { return Progress.getProgress(); }, function (newValue, oldValue) {
if (newValue !== oldValue) {
$scope.progress = Math.min(100, parseInt(100 * newValue / $scope.size));
if($scope.progress == 100)
{
$scope.progressModalInstance.close();
window.location.reload();
}
}
});
That is, $scope.progress in second controller should update with the value of evt.loaded in the first controller, but it doesn't.
Thanks in advance for any guidance.
EDIT: I even added the third watch parameter as true but that didn't help either.
EDIT 2 : The code above actually works to the best of my knowledge, I believe something else was causing a problem as when I reverted the code to the above after editing it due to the answers, it suddenly worked like it should. Sorry about this.
using $rootScope.$broadcast will work better for this
app.factory('Progress', function ($rootScope) {
var data = {
progressPercentageLoaded: 0
};
return {
getProgress: function () {
$rootScope.$broadcast('Event');
return data.progressPercentageLoaded;
},
setProgress: function (progress) {
data.progressPercentageLoaded = progress;
}
};
});
In your second controller instead of using watch
something like
$rootScope.$on('Event', function(){
//your logic here
})
You are losing the reference because you are watching the Int value that you are updating every time, hence you are changing the reference. You have to watch the whole object progressPercentageLoaded.
You have to pass true as the last parameter of the $watch function so that the equality check is angular.equals. Otherwise, only reference equality is checked.
I'm not 100% sure, but Angular may not be aware of the file upload event. Try calling $apply:
$scope.$apply(function() {
Progress.setProgress($scope.progressPercentageLoaded.progress);
});

How do you reset a “$timeout”, and disable a “$watch()” angularJS?

How do you reset a $timeout, and disable a $watch()?
The key to both is assigning the result of the function to a variable.
To cleanup the timeout, just “.cancel()” it:
var customTimeout = $timeout(function () {
// arbitrary code
}, 55);
$timeout.cancel(customTimeout);
The same applies to “$interval()”.
To disable a watch, just call it.
var deregisterWatchFn = $rootScope.$watch(‘someGloballyAvailableProperty’, function (newVal) {
if (newVal) {
// we invoke that deregistration function, to disable the watch
deregisterWatchFn();
...
}
});
You already got most of the answer, but one other point that might be useful is that you should always clean up a watch when the relevant scope is destroyed, so the following pattern is quite useful:
$scope.$on('$destroy', $scope.$watch(function() { /* ... */ });
This will ensure the $watch is always cancelled automatically on destruction of the scope.
Of course if you want to destroy the watch manually you would have to also save the result so you could call it, but this pattern lets you avoid that most of the time.
You can clear a $timeout by using $timeout.cancel like so:
var myTimer = $timeout(function() { /* ... */ }, 5000);
$timeout.cancel(yourTimer);
You can clear a $watch() by the deregister function it returns:
var dereg = $scope.$watch(function() { /* ... */ });
dereg(); // watcher is now gone

angularJS: Function in function

Hello I'm new in angularJS. Suitable or not to implement function inside function?
For example like this:-
$scope.loadDistrict = function(id) {
// statement
$scope.loadBasedOnYear = function(y_id) {
console.log(y_id);
// statement
};
};
If you bind method on scope, it's available from view.
From your code
$scope.loadDistrict = function(id) {
// statement
$scope.loadBasedOnYear = function(y_id) {
console.log(y_id);
// statement
};
};
loadBasedOnYear won't available until loadDistrict is called.
It's very bad pattern to follow.
It is possible but without context I don't really know why you would do this, calling $scope.loadBasedOnYear before calling $scope.loadDistrict will result in an error so be careful with such a design pattern.
Yes this is fine.
You should watch out for when the function will be executed outside of angular's cycle. E.g. if you do:
setTimeout(function() { $scope.test = 5; }, 1000);
If you need to do this then you need to wrap the function in $scope.$apply(), or use $timeout.

how to invoke a method in the scope using $timeout

I'm attempting to use $timeout to invoke one function that I have, but I don't know how to invoke a function that is in the $scope. Let me exemplify
I have this:
$scope.play = function(){
// function implementation
if(condition()){
$timeout(play, 1000);
}
}
it doesn't recognize the play function, I have also tried this
$timeout($scope.play, 1000);
and it also doesn't work. I had to work around it like this:
var play = function(){
$scope.playInner();
}
$scope.playInner = function(){
// function implementation
if(condition()){
$timeout(play, 1000);
}
}
But I'm sure there's a better way to do this, does anyone know how I can do that?
as JB Nizet suggested, $timeout($scope.play, 1000) should work fine.
Example:
function ctrl($scope,$timeout){
$scope.data=0;
$scope.play=function(){
$scope.data++;
$timeout($scope.play,1000);
}
}
Live example: http://jsfiddle.net/choroshin/wF8SZ/

Angularjs adding $scope.$watch after $routeProvider's resolve

I'm having an issue where I am trying to watch a certain element from my scope after the resolve is done. For some reason, it gets run when i run the second line from this snippet and I dont seem to be able to add this $watch during the "resolve".
I understand that promises are asynch, but how can I know when my resolve is done to then add the watch?
The variableToWatch can be changed either by code or in the UI (otherwise i would've just used ng-change="doWork()")
$scope.variableToWatch = $route.current.locals.data.initialValue;
$scope.listOfDependantData = $route.current.locals.data.items;
$scope.$watch('variableToWatch', function (newValue) {
myService.getNewDependantData(newValue).$promise.then(
function (items) {
$scope.listOfDependantData = items;
}
);
};
Update:
If you want to run your code only when it changes after the initial setting of value, you can use the second form of the watchFunc passed as the second argument to $scope.$watch:
$scope.$watch('variableToWatch', function (newValue, oldValue) {
if (typeof newValue !== 'undefined' && newValue !== oldValue) {
// Use the new value here ...
}
});
I don't fully follow the question, but I suspect that you want to watch the value $route.current.locals.data.initialValue instead of $scope.varibleToWatch?
In that case, you can use the alternate form of $scope.$watch with a function as the first argument:
$scope.$watch(function () { return $route.current.local.data.intialValue; }, function (newValue) {
// ...
};
Or, if you want to watch the variable on your $scope which is referenced to by the sting contained in $route.current.local.data.initialValue, then you can use this:
$scope.$watch(function () { return $scope[$route.current.local.data.intialValue]; }, function (newValue) {
// ...
};
Does this solve your problem?

Resources