How can i make angular apply the changes to the view before exiting the click method? In the following example i want the span to be visible while the confirm box is shown.
$scope.click = function () {
$scope.saving = true; //Not enough
$scope.$apply(function () {
$scope.saving = true;
});//Throws error but works [$rootScope:inprog] $apply already in progress
confirm('Are you sure?');
$scope.saving = false;
}
<span ng-show="saving">Loading ... </span>
Plunker
What you want to do is doing part of your code in one digest cycle of Angular and the rest in another. I accomplish this by using a small timeout:
$scope.click = function () {
$scope.saving = true;
$timeout(function() {
confirm('Are you sure?');
$scope.saving = false;
}, 50);
}
NB: Don't forget to add $timeout to the dependencies of your controller
Related
Is there a way to add a timeout to an AngularJS $watch function?
For example, let's say I have the below AngularJS code that's watching a value, myName. When the value changes, the listener function runs. But if the value does not change within a certain period of time, I want it to do something else.
Specifically, in the code below, I would want $scope.nothingEnteredFlag to change from false to true. My html template be set up to reflect the state of that flag (e.g., using ng-show).
var app = angular.module("helloApp", []);
app.controller("helloCtrl", function($scope) {
$scope.nothingEnteredFlag=false;
$scope.$watch("myName", function (newValue, oldValue) {
if ($scope.myName.length < 5) {
$scope.message = "Short name!";
} else {
$scope.message = "Long name!";
}
});
});
See fiddle.
I've tried surrounding the $watch with $timeout, but can't seem to get that to work.
You can use angular timeout to achieve your desire result.
var timer;
var timerFunction = function() {
timer = $timeout(function() {
$scope.nothingEnteredFlag = true;
}, 5000);
};
This is will create the timer function
Your controller should like this
var app = angular.module("helloApp", []);
app.controller("helloCtrl", function($scope, $timeout) {
$scope.nothingEnteredFlag = false;
$scope.myName = "";
$scope.$watch("myName", function(newValue, oldValue) {
if ($scope.myName.length < 5) {
$scope.message = "Short name!";
} else {
$scope.message = "Long name!";
}
$scope.nothingEnteredFlag = false;
$timeout.cancel(timer);
timerFunction();
});
var timer;
var timerFunction = function() {
timer = $timeout(function() {
$scope.nothingEnteredFlag = true;
}, 5000);
};
timerFunction();
});
As you can see we have enabled timeout of the 5 seconds once user enters any text we cancel the timer and enable it again, this way we can prompt the user to enter if he hasn't wrote anything in five seconds.
Demo
I'm very new to angularjs and I want to establish a connection to my server and dynamically show the result to user. so far I've tried:
angular.module('myApp.controllers', []).controller('socketsController', function($scope) {
$scope.socket = {
client: null,
stomp: null
};
$scope.reconnect = function() {
setTimeout($scope.initSockets, 10000);
};
$scope.notify = function(message) {
$scope.result = message.body;
};
$scope.initSockets = function() {
$scope.socket.client = new SockJS('/resources');
$scope.socket.stomp = Stomp.over($scope.socket.client);
$scope.socket.stomp.connect({}, function() {
$scope.socket.stomp.subscribe('/user/topic/messages', $scope.notify);
});
$scope.socket.client.onclose = $scope.reconnect;
};
$scope.initSockets();
});
But when I use {{result}} nothing appears.
UPDATE
The server response is totally right with console.log(message.body).
I guess, the callback is not taking the scope properly. Try call $scope.$apply(); after you attach the message.body to result :
$scope.notify = function(message) {
$scope.result = message.body;
$scope.$apply();
};
$scope.$apply() triggers an angular digest cycle whcih will update all the bindings..
Call it inside a timeout function but inject $timeout first it will call the digest cycle and update the value.
$timeout(function(){
$scope.result = message.body;});
I am implementing a spinner functionality in my project. The gold is to show the spinner when one or multiple http requests are fired, and hide the spinner when the requests are successful. Because I don't know which request will be resolved first, I chose to use $q.all. I have a directive like this:
angular.module('myApp', [])
.directive('spinner', function($q, $http) {
return {
controller: function($scope) {
$scope.showSpinner = true;
var self = this;
self.promises = [];
self.makeHeader = function() {
self.promises.push($http.get('some/url'));
// Code that builds header goes here.
};
self.makeFooter = function() {
self.promises.push($http.get('other/url'));
// Code that builds footer goes here.
};
self.makeHeader();
self.makeFooter();
// Initial page load
$q.all(self.promises).then(function() {
// Hide the spinner.
$scope.showSpinner = false;
});
}
}
});
The initial load works fine, but when user has an interaction which requires multiple calls to server, to rebuild the header and footer. How do I show the spinner again and hide it when the promises are resolved?
You can wrap the repeated calls into a function.
I also recommend to make the 2 functions to return promise instead of handling the $http promise inside to provide more flexibility.
angular.module('myApp', [])
.directive('spinner', function($q, $http) {
return {
controller: function($scope) {
var self = this;
self.makeHeader = function() {
return $http.get('some/url').then(function() {
// Code that builds header goes here.
});
};
self.makeFooter = function() {
return $http.get('other/url').then(function() {
// Code that builds footer goes here.
});
};
self.build = function() {
$scope.showSpinner = true;
self.promises = [];
self.promises.push(self.makeHeader());
self.promises.push(self.makeFooter());
$q.all(self.promises).then(function() {
// Hide the spinner.
$scope.showSpinner = false;
});
}
// initial run
self.build();
// subsequent call
self.someClickHandler = function() {
self.build();
}
// some other calls that need to use spinner
self.other = function() {
$scope.showSpinner = true;
self.promises = [];
self.promises.push(self.otherCall());
$q.all(self.promises).then(function() {
// Hide the spinner.
$scope.showSpinner = false;
});
}
}
}
});
As you can see this approach would look better if you always call same set of functions every time, but what if you need to use spinner on other cases like self.other?
You can wrap the spinner in a function and pass it the promise array.
var showSpinner = function(promises) {
$scope.showSpinner = true;
$q.all(promises).then(function() {
// Hide the spinner.
$scope.showSpinner = false;
});
}
self.build = function() {
var promises = [];
promises.push(self.makeHeader());
promises.push(self.makeFooter());
showSpinner(promises);
}
self.other = function() {
var promises = [];
promises.push(self.otherCall());
showSpinner(promises);
}
Looks cleaner?
Can someone explain why spinerChange() function do not work properly? http://jsfiddle.net/HB7LU/9907/
<div ng-controller="naujienosControler">
<button type="button" ng-click="spinerButtonChange()">Click Me!</button>
<div class="spinner" ng-show="spiner" >
<div class="cube1"></div>
<div class="cube2"></div>
</div>
</div>
var myApp = angular.module('myApp',[]);
myApp.controller('naujienosControler', function ($scope) {
var status = true;
$scope.spiner = status;
$scope.spinerButtonChange = function(){$scope.spiner = !$scope.spiner;};
function spinerChange(){
setTimeout(function(){ alert("Why spiner dont disapear?????????"); $scope.spiner = false;}, 3000);
console.log($scope.spiner);
};
spinerChange();
});
Inject and use $timeout since you want angular to perform a digest after you do you action.
myApp.controller('naujienosControler', function ($scope, $timeout){
$timeout(function(){ $scope.spiner = false; }, 3000});
}
Edit (Thanks lechariotdor) : It's always a good practice to use "the angularjs world" wrappers since they run the $apply method that performs a digest on your scope and "syncs" the model with the change that occured.
because javascript setTimeout is a event which is not trigger in angularjs scope, so angular doesn't know about changes outside the scope.
there is a way to achieve is use $timeout instead of setTimeout as below, here is the DOC for $timeout
$timeout(function() {
$scope.spiner = !$scope.spiner;
}, 3000)
and don't forget to inject $timeout in to the controller as,
myApp.controller('naujienosControler', function ($scope, $timeout) {....
here is the update
there is another alternative using $scope.$appy() here is a good tutorial about $apply()
function spinerChange(){
setTimeout(function(){
$scope.spiner = !$scope.spiner;
$scope.$apply();
}, 3000);
};
spinerChange();
});
OR
function spinerChange(){
setTimeout(function(){
$scope.$apply(function() {
$scope.spiner = !$scope.spiner;
});
}, 3000);
};
spinerChange();
});
Use :-
$timeout(function(){ alert("Why spiner dont disapear?????????"); $scope.spiner = false;}, 500);
I want to wait some time after click, then processed.
i tried:
<button ng-click="$timeout(save,500);">Save<button>
controller
$scope.save = function() {
// save.
}
no error in console.
what i doing wrong?
As 'Paolo Moretti' said, the way to use $timeout in ng-click markup is attach the $timeout service to $scope.
HTML
<button ng-click="$timeout(save,500);">Save<button>
Javascript
$scope.$timeout = $timeout; // must be injected in controller.
$scope.save = function() {
// save.
}
Move the code to your controller:
<button ng-click="clickHandler()">DO-IT<button>
$scope.clickHandler = function() {
$timeout($scope.save, 500);
}
$scope.save = function() {
// save
}