how to use $timeout in ng-click markup - angularjs

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
}

Related

AngularJs unit-test for timeout

I have a angular directive with the following snippet of code, how would I unit test this?
link: function($scope, iElm) {
$(iElm).on('paste', function(){
$timeout(function(){
$scope.lastScan = Date.now();
});
});
}
You need to use $timeout.flush() which will instantly call any $timeout callbacks you have defined, so it essentially makes it into synchronous code for testing purposes.
Try this:
DEMO
app.js
app.directive('myDirective', function($timeout){
return function($scope, iElm) {
// no need to use jQuery
iElm.bind('paste', function(){
console.log('**paste**')
$timeout(function(){
console.log('timeout')
$scope.lastScan = Date.now();
});
});
// $(iElm).on('paste', function(){
// $timeout(function(){
// $scope.lastScan = Date.now();
// });
// });
}
});
appSpec.js
describe("My directive", function() {
var element,
$timeout, $compile, $scope;
// load the module that has your directive
beforeEach(module('plunker'));
beforeEach(inject(function(_$timeout_, _$compile_, _$rootScope_) {
$timeout = _$timeout_;
$compile = _$compile_;
$scope = _$rootScope_.$new();
}));
function compileElement(){
// use $compile service to create an instance of the directive
// that we can test against
element = $compile('<my-directive></my-directive>')($scope);
// manually update scope
$scope.$digest();
}
it("defines a 'lastScan' property", function() {
compileElement();
// trigger paste event
element.triggerHandler('paste');
// angular doesn't know about paste event so need
// to manually update scope
$scope.$digest();
// immediately call $timeout callback
// thus removing any asynchronous awkwardness
$timeout.flush();
// assert that directive has added property to the scope
expect($scope.lastScan).toBeDefined();
});
});

ng-show do not change when i fire function

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);

Angularjs Apply scope change to view immediately

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

Asynchronous request and loading button with AngularJS

DOM manipulation within an Angular controller seems to be wrong. But this is not coming without a few headaches :)
I have a button, and on ng-click, it will perform an asynchronous request in the background. During the time of that asynchronous request I would like all the buttons (and maybe a few more elements on the page) to be disabled and the clicked button to have a loading icons playing.
What is the cleanest way of doing this?
I usually do this with a variable on the $scope called loading. Whenever an asynch operation is happening, just set it to true. Then anything that's need to be disabled or otherwise affected can base it's state off of that.
Here's a dummy control:
function TestCtrl($scope, $http) {
$scope.loading = false;
$scope.doASynch = function () {
$scope.loading = true;
$http.get("/url").success(function () {
$scope.loading = false;
});
}
}
And here's a sample template.
<div ng-controller="TestCtrl">
<a class="button" ng-disabled="loading" ng-click="doASynch()">
<span ng-hide="loading">Click me!</span>
<span ng-show="loading">Loading....</span>
</a>
</div>
Here is exactly what you are looking for
Loading animations with Asynchronous HTTP Requests in Angular JS
var app = angular.module('myapp', ["ui.utils", "ui.router"]);
app.factory('iTunesData', function($http) {
return {
doSearch: function(sQuery) {
//return the promise directly.
return $http.jsonp('http://itunes.apple.com/search', {
params: {
"callback": "JSON_CALLBACK",
"term": sQuery
}
});
}
}
});
app.controller('iTunesSearch', function($scope, $location, $routeParams, iTunesData) {
$scope.search = function() {
iTunesData2.doSearch($scope.searchTerm)
.then(function(result) {
$scope.data = result.data;
$location.path($scope.searchTerm);
});
}
$scope.searchTerm = $location.$$path.split("/")[1];
if($scope.searchTerm!="") {
$scope.search();
}
});

AngularJS : Basic $watch not working

I'm attempting to set up a watch in AngularJS and I'm clearly doing something wrong, but I can't quite figure it out. The watch is firing on the immediate page load, but when I change the watched value it's not firing. For the record, I've also set up the watch on an anonymous function to return the watched variable, but I have the exact same results.
I've rigged up a minimal example below, doing everything in the controller. If it makes a difference, my actual code is hooked up in directives, but both are failing in the same way. I feel like there's got to be something basic I'm missing, but I just don't see it.
HTML:
<div ng-app="testApp">
<div ng-controller="testCtrl">
</div>
</div>
JS:
var app = angular.module('testApp', []);
function testCtrl($scope) {
$scope.hello = 0;
var t = setTimeout( function() {
$scope.hello++;
console.log($scope.hello);
}, 5000);
$scope.$watch('hello', function() { console.log('watch!'); });
}
The timeout works, hello increments, but the watch doesn't fire.
Demo at http://jsfiddle.net/pvYSu/
It's because you update the value without Angular knowing.
You should use the $timeout service instead of setTimeout, and you won't need to worry about that problem.
function testCtrl($scope, $timeout) {
$scope.hello = 0;
var t = $timeout( function() {
$scope.hello++;
console.log($scope.hello);
}, 5000);
$scope.$watch('hello', function() { console.log('watch!'); });
}
Or you could call $scope.$apply(); to force angular to recheck the values and call watches if necessary.
var t = setTimeout( function() {
$scope.hello++;
console.log($scope.hello);
$scope.$apply();
}, 5000);
You can use without $interval and $timeout
$scope.$watch(function() {
return variableToWatch;
}, function(newVal, oldVal) {
if (newVal !== oldVal) {
//custom logic goes here......
}
}, true);
It can also happen because the div is not registered with the controller. Add a controller to your div as follows and your watch should work:
<div ng-controller="myController">

Resources