Is it possible to know, that request is processing - javascript

I have a lot of pages, where i use $http to process requests (get data, update) and i have to use ajax-loading.gif every time.
Now, i need to do it like this:
<div ng-show="model == null || ajaxUpdating">
<div>
<img src="~/Content/Images/gif-load.gif" />
<p>Waiting server respone...</p>
</div>
</div>
Here i have ajaxUpdating flag, that i init before request and set false in success or error callbacks:
$scope.ajaxUpdating = true;
$http({
url: updateUrl,
method: 'POST'
}).
success(function (data, status) {
window.location.href = settings.redirectAfterOk;
}).
error(function (data, status) {
$scope.ajaxUpdating = false;
alert(data.errorMsg || settings.errors.update);
});
So, i wanna know, is it possible to check, if request processing right now? I don't want to use so many flags every where in my code and it could be much easier, if i just write:
$http.isProcessing
for example.
Thx you.

If you need a loading gif whenever an ajax http request is in progress, you can set an interceptor on the config like this:
var myApp = angular.module('myApp', []).config(
[ '$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
//routes here
}]).config(function($httpProvider) {
//show a loading div when a http request is running
var numLoadings = 0;
var loadingScreen = $('<div style="position:fixed;top:0;left:0;right:0;bottom:0;z-index:10000;background-color:gray;background-color:rgba(70,70,70,0.2);"><img style="position:absolute;top:50%;left:50%;" alt="" src="css/loading.gif" /></div>').appendTo($('body')).hide();
$httpProvider.responseInterceptors.push(function() {
return function(promise) {
numLoadings++;
loadingScreen.show();
var hide = function(r) { if (!(--numLoadings)) loadingScreen.hide(); return r; };
return promise.then(hide, hide);
};
});
});
See $http, look for Interceptors

Related

Refresh list in ng-repeat without onclick funtion

Hello i am trying to display data from server in Angularjs App, where i got the data and use ng-repeat to display it through controller.
Here is how my controller looks like:
module.controller('FiveReasons', function($scope, $http, $rootScope, $sce) {
ons.ready(function() {
$scope.reasonsLists = {};
var reasonsListing = $http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients");
reasonsListing.success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
});
reasonsListing.error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
});
});
But when the ng-repeat finish loading, the data is not displaying.
Here is how my ng-repeat is:
<ons-carousel swipeable overscrollable auto-scroll fullscreen var="carousel" name="FiveRes" class="FiveRes">
<div ng-repeat="reasonsList in reasonsLists">
<ons-carousel-item style="background: #09a4c0;" >
<div class="item-label">Number : {{reasonsList}}</div>
</ons-carousel-item>
</div>
<ons-carousel-cover></ons-carousel-cover>
</ons-carousel>
How can i now refresh the list once the data is there. Like we do "trigger("refresh")" in jquery.
After running ng-repeat, this is how i get the value but the screen is going blank.
Thank you! (In advance)
I think in this case I'd eliminate the use of ready and call your code using ng-init.
module.controller('FiveReasons', function($scope, $http) {
this.reasonsLists = {};
$scope.getReasonsLists = function() {
$scope.reasonsLists = {};
$http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients")
.success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
})
.error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
};
});
then in your html on the table tag just add ng-init="getReasonsLists()"
Try this:
module.controller('FiveReasons', function($scope, $http, $rootScope, $sce) {
ons.ready(function() {
$scope.reasonsLists = {};
var reasonsListing = $http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients");
reasonsListing.success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
});
reasonsListing.error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
//ADD this to notify Angular for the changes and run a digest cycle
$scope.$digest();
});
});
This is happening because the event (ons-ready) handler will not start a new $digest cycle.
To display the data without having to call $digest(), remove the ons-ready callback and execute your code directly in the controllers body. Like the example bellow:
module.controller('FiveReasons', function($scope, $http, $rootScope, $sce) {
$scope.reasonsLists = {};
var reasonsListing = $http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients");
reasonsListing.success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
});
reasonsListing.error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
//No need to call $digest
});
UPDATE: Check this Codepen which is a simplified version of your code that shows only the issue. Remove $scope.$digest() from the comments to see the carousel working.
A "refresh" should not be necessary as angular uses a different approach. After certain events like "click" or the return of a $http-promise, angular goes through the binded variables and checks if they have changed - and if so - changes the DOM.
In your case I think the promise is returning before you add the success-callback. Try chaining it like:
$http.get("http://vbought.com/design_14/index.php/design_ci/post/Clients").success(function(data, status, headers, config) {
console.log(data[0].post_title);
$scope.reasonsLists = data;
$scope.spinner = false;
}).error(function(data, status, headers, config) {
alert("Can Not load the address Ajax");
});
In other cases you can use $scope.$apply() but I think this should tell you, that you can't nest $digests as there should be one going on after a $http-request.

How to add eventlisteners after simple get request json in angularjs?

Ok so I am experimenting with Angular but I have run into a problem and maybe it is because I haven't adopted the Angular way of thinking yet, but this is basically what I ran into.
I get some data with a JSON request and show this data in a list using ng-repeat. So far so good. No errors in the console, but it does not attach the eventlistener to the ng-repeat elements. The code is fine, because with non ng-repeat elements it works like a charm. Someone else ran into this problem and how did you solve it? Thanks in advance.
<div ng-controller="basictrl">
<h1>Lijst van producten</h1>
<ul ng-repeat="item in producten">
<li>{{item.naam}}</li>
<li>{{item.prijs}}</li>
</ul>
</div>
JS
angular.module("app", ['ngRoute'])
.controller("basictrl", function ($scope, $http, producteffecten) {
$scope.producten = null;
$http({
method: 'GET',
url: 'producten.json'
}).
success(function (data, status, headers, config) {
$scope.producten = data;
$scope.showdescription = producteffecten.showdescription;
}).error(function (data, status, headers, config) {});
})
.factory('producteffecten', function() {
var effecten = {};
effecten.showdescription = $('ul').hover(function (){
$(this).append("<p>Test</p>");
});
return effecten;
})
The simple answer is: you can use $('ul').on("hover",function(){}). But this is not the angular way of thinking. The first improvement you could make is this:
add ng-mouseover="muisOverEffectje()" to the ul in the html
add $scope.muisOverEffectje=function(){ your event code} to the angular page
The next step to avoid adding the code with jquery to make it even more angular could be something like this:
add a parameter which gives the selected item to your event : muisOverEffectje(item)
add ng-show="showDescription" to the the ul
put show-description to true in the event handler
The last step could be: Make a directive for you . Like a product component for example.
Setting a timeout works, but it is hacky I guess. I will try to rewrite in a more angular way.
.factory('producteffecten', function() {
var effecten = {};
//SETTING TIMEOUT WORKS SOMEHOW
effecten.showdescription = setTimeout(function() {
$('ul').hover(function (){
$(this).append("<p>Test</p>");
});
}, 10);
return effecten;
})
You could also write an directive. Which is the nicest way in angular to do this kind of stuff:
Html:
<div ng-controller="basictrl">
<h1>Lijst van producten</h1>
<ul ng-repeat="item in producten" hover-text="item.effect">
<li>{{item.naam}}</li>
<li>{{item.prijs}}</li>
</ul>
</div>
js:
.controller("basictrl", function ($scope, $http, producteffecten) {
$scope.producten = null;
$http({
method: 'GET',
url: 'producten.json'
}).
success(function (data, status, headers, config) {
$scope.producten = data;
$scope.showdescription = producteffecten.showdescription;
}).error(function (data, status, headers, config) {});
})
.directive("hoverText",function(){
return {link:function(scope,elem,attr){
var insertElem=$("<div class='hovertext'>"+scope.hoverText+"</div>")
elem .mouseenter(function() {
insertElem.appendTo(elem);
})
.mouseleave(function() {
insertElem.remove();
});
},
scope:{"hoverText":"="}
};
});

How to know which data has been changed in an array?

I'm trying to get which data has been changed in array. my use case is First time all data fetch from ajax and show within row and fetch new data using $http every 5 second. I need to know that if the new data is same as old one. If yes then which value has changed so I've to update that background to some color..
What I've already tried
var app = angular.module('app', []);
app.controller('listingController', function($scope, $http, $timeout){
$scope.listings;
setInterval(function(){
$http.get('_includes/ajax.php?req=get').
success(function(data, status, headers, config) {
$scope.listings = data;
console.log(data);
}).
error(function(data, status, headers, config) {
// log error
});
}, 5000);
});
app.controller('RentalDateController', function($scope, $log){
console.log($scope.listings);
$scope.$watch('listings.Third_Column', function (Third_Column, oldvalue) {
//$log.info(Third_Column, $scope.listings.First_Column);
console.log('being watched oldValue:', oldvalue, 'newValue:', Third_Column);
}, true);
});
My html is
<body ng-app="app">
<div ng-controller="listingController">
<table>
<tr>
<th>Testing</th>
<th>Pripse</th>
</tr>
<tr ng-repeat="row in listings" ng-controller="RentalDateController">
<input type="text" ng-model="row.Third_Column">
<input type="text" ng-model="row.First_Column">
<th>{{row.Third_Column}}</th>
<th>{{row.First_Column}}</th>
</tr>
</table>
</div>
</body>
I think I need to use $watch but it's not working.
You have the angular two-way data binding so it should automatically update your ng-repeat when the model changes.
I suggest the following
1) Remove RentalDate controller first.
2) Use $timeout, and on success of http use this
$scope.$apply(function(){
$scope.listing = data;
});
If that doesn't still automatically update, put the array in an object.
$scope.data = {}
$scope.data.listings = putArrayHere();
This will work because of this. Read up. :D
https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance
Try doing this:
var app = angular.module('app', []);
app.controller('listingController', function($scope, $http, $timeout){
$scope.listings;
var previousListing = [];
var newData;
setInterval(function(){
$http.get('_includes/ajax.php?req=get').
success(function(data, status, headers, config) {
$scope.listings = data;
console.log(data);
}).
error(function(data, status, headers, config) {
// log error
});
if( previousListing.length == $scope.listings.length )
{
console.log('No new data available.');
}
else
{
// length of the arrays are different, hence new data must be available
console.log('New data available!');
newData = $scope.listings.splice( 0, ($scope.listings.length - previousListing.length) ); // returns new data in the form of an array
console.log(newData);
previousListing = $scope.listings; // reset previous data variable
}
}, 5000);
});

AngularJS: display a select box from JSON data retrieved by http GET (from REST service)

I have a REST service that I made which returns a json string which is simply a set of strings (I used Gson to generate this string (Gson.toJson(mySetOfStrings))
So I have added to my index.html:
<div ng-controller="ListOptionsCtrl">
<form novalidate>
<button ng-click="refreshList()">refresh</button>
<select name="option" ng-model="form.option" ng-options="o.n for o in optionsList></select>
</form>
</div>
and in my script:
var ListOptionsCtrl = function ListOptionsCtrl($scope, $http) {
$scope.refreshList = function() {
$http({
method: 'GET'
url: '*someurl*'
}).
success(function(data) {
$scope.optionsList = angular.fromJson(data);
});
};
}
Unfortunately all this produces in my select box is an empty list. When I see what the response to the GET request is it returns a json string with content in it so I do not see why nothing is being added to this element. What am I doing wrong here? thanks
It is because Angular does not know about your changes yet. Because Angular allow any value to be used as a binding target. Then at the end of any JavaScript code turn, check to see if the value has changed.
You need to use $apply
var ListOptionsCtrl = function ListOptionsCtrl($scope, $http) {
$scope.refreshList = function() {
$http({
method: 'GET'
url: '*someurl*'
}).
success(function(data) {
$scope.$apply(function () {
$scope.optionsList = angular.fromJson(data);
});
});
};
}
Try this.
More about how it works and why it is needed at Jim Hoskins's post
You should check for $digest error by doing if(!$scope.$$phase) { ... } before doing $apply.
success(function(data) {
if(!$scope.$$phase) {
$scope.$apply(function () {
$scope.optionsList = angular.fromJson(data);
});
}
});

fire a event after finish write in angularjs

I would like fire a search after my user finish write (without a enter) in angularjs.
My html (simplified):
<div ng-class="input-append" ng-controller="searchControl">
<input type="text" ng-model="ajaxSearch" ng-change="search();">
</div>
My AngularJs (simplified):
$scope.searchControl = function() {
$scope.search = function(){
$http({
method: 'POST',
url: '<?php echo base_url('system/ajax_search/') ?>',
'data: search=' + $scope.ajaxSearch,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).success(function(data) {
$scope.result = data;
});
}
The original code is extensive, so i simplified.
In my code, i post data always my user change the search.
I would like post data seconds after my user stop to write.
Any ideas?
This can be easily achieved with a directive:
angular.module('myApp', [])
.directive('keyboardPoster', function($parse, $timeout){
var DELAY_TIME_BEFORE_POSTING = 3000;
return function(scope, elem, attrs) {
var element = angular.element(elem)[0];
var currentTimeout = null;
element.onkeypress = function() {
var model = $parse(attrs.postFunction);
var poster = model(scope);
if(currentTimeout) {
$timeout.cancel(currentTimeout)
}
currentTimeout = $timeout(function(){
poster();
}, DELAY_TIME_BEFORE_POSTING)
}
}
})
.controller('testController', function($scope){
$scope.search = function() {
console.log("Executing query...");
}
})
And it can be used like this...
<div ng-app='myApp' ng-controller='testController'>
<input type="text" keyboard-poster post-function="search">
</div>
Use $timeout and cancel each time user types; if the timeout runs, executes the scoped function given as an attr. You can modify the delay time to whatever fits better your user experience (I wouldn't drop it below 1000 though).

Categories