Angular ui grid how to show a loader - javascript

I'm wondering how to show a simple loader before data was loaded.
I'm using ng-grid-1.3.2
I'm googling but I didn't find any example.
Bye

like Maxim Shoustin suggested you can use the angularjs-spinner from Jim Lavin which uses (deprecated) Response Interceptors.
I think it's explained best here :
http://codingsmackdown.tv/blog/2013/04/20/using-response-interceptors-to-show-and-hide-a-loading-widget-redux/
In a nutshell, in his first solution, what you have to do for your ng-grid app is:
1) Add the loading gif to your html (for loading gif look here)
<div id="loadingWidget" class="row-fluid ui-corner-all" style="padding: 0 .7em;" loading-widget >
<div class="loadingContent">
<p>
<img alt="Loading Content" src="images/ajax-loader.gif" /> Loading
</p>
</div>
</div>
2) In your code as soon as you have declared your app level module add the Response Interceptors for http requests to the configuration block
var app = angular.module('myCoolGridApp', ['ngGrid']);
app.constant('_START_REQUEST_', '_START_REQUEST_');
app.constant('_END_REQUEST_', '_END_REQUEST_');
app.config(['$httpProvider', '_START_REQUEST_', '_END_REQUEST_', function ($httpProvider, _START_REQUEST_, _END_REQUEST_) {
var $http,
interceptor = /* see extra details on codingsmackdown.tv */
$httpProvider.responseInterceptors.push(interceptor);
}
3) and then add your loadingWidget directive
app.directive('loadingWidget', ['_START_REQUEST_', '_END_REQUEST_', function (_START_REQUEST_, _END_REQUEST_) {
return {
restrict: "A",
link: function (scope, element) {
element.hide();
scope.$on(_START_REQUEST_, function () {element.show();});
scope.$on(_END_REQUEST_, function () {element.hide();});
}
};
}]);
See more details at codingsmackdown

I had the same question as you.
I find this nice tutorial about it: http://brianhann.com/ui-grid-the-easiest-customization-youll-ever-write/
He use vm.loading = true while fetching data from server and changed to false after complete.
var app = angular.module('app', ['ngTouch', 'ui.grid']);
app.controller('MainCtrl', ['$http', '$timeout', function ($http, $timeout) {
var vm = this;
vm.reset = reset;
vm.noData = noData;
vm.gridOptions = {
columnDefs: [
{ field: 'name' },
{ field: 'age' }
]
};
reset();
////////////
// Initialize our data source
function init() {
$http.get('data.json')
.success(function (data) {
vm.gridOptions.data = data;
})
.finally(function () {
vm.loading = false;
});
}
// Reset the data source in a timeout so we can see the loading message
function reset() {
vm.loading = true;
vm.gridOptions.data = [];
$timeout(function () {
init();
}, 1000);
}
function noData() {
vm.gridOptions.data = [];
}
}]);
In the HTML, he uses ng-hide to show/hide the spinner based on values of gridOptions.data and vm.loading:
<div id="grid1" ui-grid="vm.gridOptions" class="grid">
<div class="grid-msg-overlay" ng-hide="!vm.loading">
<div class="msg">
<span>
Loading Data...
<i class="fa fa-spinner fa-spin"></i>
</span>
</div>
</div>
<div class="grid-msg-overlay" ng-hide="vm.loading || vm.gridOptions.data.length">
<div class="msg">
<span>No Data</span>
</div>
</div>
</div>
Here is the Plunker of the final version shown.

You have angularjs-spinner, see GitHub sources

I also needed a similar behavior and I came across this answer but I needed to show something inside the grid itself so here is something I put together. My idea is that I change the gridOptions on the fly and show a loader as a row inside the grid.
loaderOptions = {
"columnDefs": [{
"name": "",
"field": "loading",
"enableColumnMenu": false,
"cellTemplate": '<div style="width:90px; margin:auto;"><span class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></span> Loading...</div>'
}],
"data": [{
"loading": ""
}]
};

Simply,by adding this code in your html part:
<img alt="loading..." src='images/ajax-loader.gif")' /> loading message...
and the following code in your app.controller script:
$http.get(yourdataUrl)
.then(function (response) {
$scope.records = response.data;
$("#loadingWidget").hide();
});
it works fine for me!

The HTML code-sample
<img ng-show="loading" src="~/img/loding.jpg" />
<div class="ngtyle" ng-grid="myGridView"></div>
The AngularJs code-sample
var app = angular.module('App', ['ngGrid']);
app.controller('MainCtrl', function ( $scope, myService ) {
$scope.loading = true;
myService.get().then( function ( response ) {
$scope.items = response.data;
})
.finally(function() {
$scope.loading = false;
});
$scope.myGridView = {
data: 'dataList',
columnDefs: 'myDisplayColumns'};
});

Related

Angularjs language localization

Why after invoking English() or France() functions value of $scope.currentLanguageId in myFilter does not change?
Is it normal way to make different localization of site by filters? Or existing may be more common way?
List:
<div ng-init="GetList()">
<div ng-repeat="item in items | filter: myFilter">
{{item.Text}} {{item.LanguageId}}
</div>
</div>
Menu:
<div class="menu">
<ul>
<li>About</li>
<li>Contacts</li>
<li><a>Test</a></li>
<li><a>Test</a></li>
<li><a>Test</a></li>
<li><input type="button" value="En" ng-controller="homeController" ng-click="English()" /></li>
<!--<li><a>En</a></li>
<li><a>Fr</a></li>-->
</ul>
</div>
Controller:
app.controller('homeController', function ($scope, $http) {
$scope.items = [];
$scope.currentLanguageId = '';
$scope.GetList = function () {
$http({
method: 'GET',
url: '/Home/GetList',
params: { languageId: '1'}
}).then(function successCallback(response) {
$.each(response.data, function (id,item) {
$scope.items.push({ Text: item.Text, LanguageId: item.LanguageId });
});
}, function errorCallback(response) {
alert('Error');
});
}
$scope.English = function () {
$scope.currentLanguageId = '2';
}
$scope.France = function () {
$scope.currentLanguageId = '3';
}
$scope.myFilter = function (item) {
console.log($scope.currentLanguageId);
return item.LanguageId == $scope.currentLanguageId;
};
});
DEMO
I would create a service for that, and attach it to the $rootScope so it is available everywhere in my application and does not need to be injected in each controller
var app = angular.module('app', []);
app.run(function(langService){
langService.fetch('spanish');
});
app.controller('MainController', function(){
var vm = this;
});
app.service('langService', function($rootScope){
this.current = {};
this.fetch = function(lang){
//do your fetching here with $http
$rootScope.lang = {
ok: 'si',
yes: 'si',
no: 'no'
};
};
});
then you can use it anywhere in your app like
<button>{{$root.lang.ok}}</button>
<button>{{$root.lang.no}}</button>
Other things worth pointing out:
Your controller is too fat, you should not put logic on your controller, logic should be in services
Avoid using ng-init as much as possible, do it inside the controller

ng-show - using a service as a scope parameter

I'm writing an angular 1.5.0-rc0 application using bootstrap for a nav bar component.
I want to show the user an added items to his navigation bar if his user group id is 1.
first I created a service:
app.factory('UserService', function() {
return {
userGroupId : null
};
});
I created the nav bar as a directive, so i included it in the main html file
<nav-bar></nav-bar>
and the nav-bar directive code:
(function () {
angular.module('myalcoholist').directive('navBar', function () {
return {
restrict: 'E',
templateUrl: 'views/nav.html',
controller: ['$scope','$auth', 'UserService',function ($scope,$auth,UserService) {
$scope.user=UserService;
$scope.isAuthenticated = function()
{
return $auth.isAuthenticated();
};
}]
}
});
})();
as you can see I set $scope.user as the returned object from UserService.
in my login controller, after a successful login I set the userGroupId.
angular.module('myalcoholist').controller('LoginController',['$scope','$auth','$location', 'toastr','UserService',function ($scope,$auth,$location,toastr,UserService) {
$scope.authenticate = function (provider) {
$auth.authenticate(provider).then(function (data) {
var accessToken = data.data.token;
apiKey=accessToken;
UserService.userGroupId=data.data.user_group_id;
...
now.. my nav-bar template file is as the following code:
<li ng-show="user.userGroupId == 1">
Admin Drinks
</li>
even after the authentication, when I uset userGroupId to 1 the element is still not shown.
any ideas?
update
I debugged and noticed that UserService.userGroupId is still null. so
I changed the UserService to have the following code:
app.factory('UserService', function() {
var user = {userGroupId:null};
return {
setUserGroupId: function (userGroupId) {
user.userGroupId=setUserGroupId;
},
getUserGroupId: function () {
return user.userGroupId;
}
};
});
in my LoginController I now try to execute setUserGroupId:
angular.module('myalcoholist').controller('LoginController',['$scope','$auth','$location', 'toastr','UserService',function ($scope,$auth,$location,toastr,UserService) {
$scope.authenticate = function (provider) {
$auth.authenticate(provider).then(function (data) {
var accessToken = data.data.token;
apiKey=accessToken;
UserService.setUserGroupId(data.data.user_group_id);
...
when I debug i see that userService is an object with two functions as I defined, but when the javascript chrome debugger tries to execute this line:
UserService.setUserGroupId(data.data.user_group_id);
I get the following error:
ReferenceError: setUserGroupId is not defined
at Object.setUserGroupId (app.js:21)
at login-controller.js:12
at angular.js:15287
at m.$eval (angular.js:16554)
at m.$digest (angular.js:16372)
at m.$apply (angular.js:16662)
at g (angular.js:11033)
at t (angular.js:11231)
at XMLHttpRequest.v.onload (angular.js:11172)
I have created a fiddle showcasing your requirement (as close as possible), and it seems to work fine.
http://jsfiddle.net/HB7LU/21493/
My guess is that you aren't actually setting the value when you think you are, and will likely require some debugging. Here is the code for brevity.
HTML
<div ng-controller="MyCtrl">
<div ng-click="clicked()">
Click ME, {{user.value}}!
</div>
<test-dir></test-dir>
</div>
JS
angular.module('myApp',[])
.service('TestService', function(){
return {
value: 2
};
})
.directive('testDir', function(){
return {
restrict: 'E',
template: '<div ng-show="user.value === 1">Here is some text</div><div>Some more always showing</div>',
controller: function ($scope, TestService) {
$scope.user = TestService;
}
};
})
.controller('MyCtrl', function($scope, TestService){
$scope.user = TestService;
$scope.clicked = function(){
TestService.value = 1;
};
});

Call 2 functions in single ng-click

I am calling two functions on ng-click. But it doesn't work. I am not sure why the Refresh1() is not called when I cross-checked through debugger.
HTML CODE
<div class="row" ng-controller="PublishManifestCtrl">
<div class="col-xs-12 col-md-12">
<div class="widget">
<div class="widget-header bordered-bottom bordered-themeprimary">
<i class="widget-icon fa fa-tasks themeprimary"></i>
<span class="widget-caption themeprimary">Manifest Status</span>
</div>
<div class="widget-body">
<form class="form-bordered" role="form">
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last published to agents on <b>{{manifeststatus.manifestLastPublishedDate}}</b>.</label>
</div>
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last updated by <b> {{manifeststatus.lastUpdatedByUser}} </b> on <b>{{manifeststatus.manifestLastedUpdatedDate}}</b>.</label>
</div>
<div class="form-group">
<div class="col-sm-offset-1">
**<button id="PublishButton" class="btn btn-default shiny " ng-disabled="manifeststatus.enablePublishButton" ng-click="Save(manifeststatus);Refresh1()">Publish</button>**
</div>
<br/>
<div id="statusDivPublish" ng-show="showstatus">
<alert type="{{alert.type}}">{{alert.msg}}</alert>
</div>
</div>
</form>
</div>
JSFILE
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
}
$scope.Refresh1 = function () {
//refresh
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
}
});
new code
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.Refresh1();
}
$scope.Refresh1 = function ($rootScope, $state, $stateParams) {
debugger;
return {
restrict: 'AC',
link: function (scope, el, attr) {
el.on('click', function () {
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
});
}
};
};
});
The first one updates and displays a successfull message, while the second function refreshes the page.
use this
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
call refresh inside the first function and remove it from the ng-click.
Update
You have a different type of problem i had it too. you try to refresh a state inside a method, it's really difficult i solve that problem with this snippet
if($state.current.name == /*name of the current state*/) {
$state.go($state.current, {}, {reload: true});
$modalInstance.close();
}
else {
$modalInstance.close();
$state.go(/*name of the current state*/);
}
it's not difficult but it didn't behave like you have understand it.
UPDATE
taking your code
$scope.Refresh1 = function () {
//refresh
$state.go($state.current, {}, {reload: true});
}
What about calling refresh inside of save in $http handler ?
Like this:
$http.post($rootScope.WebApiURL + '/updatemanifeststatus')
.then(function(){
$scope.Refresh1();
});
Don't execute two function in one ng-click, instead add the Refresh1 call to the end of the Save call, like so.
HTML
<button id="PublishButton"
class="btn btn-default shiny "
ng-disabled="manifeststatus.enablePublishButton"
ng-click="Save(manifeststatus)">Publish</button>
JS
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
Update
If you are using AngularJS V1.2.2 or higher, then using ui-router, the following should work to reload the data.
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
The shortest way to accomplish this though would be with:
$state.go($state.current, {}, {reload: true}); //second parameter is for $stateParams
Its also worth noting that none of these will actually reload the page. If you want to reload the state AND the page, there is no ui-routermethod for it. Do window.location.reload(true)
Update 2
If you are receiving:
$state is not defined at Scope.$scope.Refresh1
(publishmanifest.js:44) at Scope.$scope.Save (publishmanifest.js:37)
at $parseFunctionCall (angular.js:12345) at angular-touch.js:472 at
Scope.$eval (angular.js:14401) at Scope.$apply (angular.js:14500) at
HTMLButtonElement. (angular-touch.js:471) at
HTMLButtonElement.n.event.dispatch (jquery.min.js:3) at
HTMLButtonElement.r.handle (jquery.min.js:3)
You are not injecting the $state service in your controller. You must do this in order to use it.
//without annotation (inferred, not safe when minifying code)
function Controller($scope, $state) {...}
//inline annotation
module.controller('Controller', ['$scope','$state', function($scope, $state) {...}]);
//$inject property annotation
function Controller($scope, $state) {...}
Controller.$inject = ['$scope', '$state'];
Pick one of the methods above to setup your controller to use $state.
Just make a third function like:
function3(data) {
save(data);
refresh1();
}

Why is angular-promise-tracker not working for me?

I've installed angular-promise-tracker and I think I'm close to getting it working. The problem I'm having is that the "loading" text isn't showing. The data is fetched and does show when outputting it to the console.
So it appears that ng-show="loadingTracker.active()" isn't working. I can't see what I'm doing wrong with this.
Any help with this would be sincerely appreciated - as always :)
Here's my code:
HTML
<button ng-controller="weatherCtrl"
ng-model="hotel"
class="btn btn-default"
ng-click="loadWeather(hotel, $index)">
{{buttonText}} more</button>
<div collapse="isCollapsed">
<div class="well well-lg more-detail">
{{hotel.Description}}
<br /><br />
<div>
<div class="my-super-awesome-loading-box"
ng-show="loadingTracker.active()">
Loading..
</div>
</div>
</div>
</div>
JS
.controller('weatherCtrl', function ($scope, weather, $timeout, promiseTracker){
$scope.loadingTracker = promiseTracker();
$scope.buttonText= 'Load'
$scope.loadedHotelDetails=[];
$scope.loadWeather = function(hotel, index) {
// console.log('loadWeather')
weather.get({tracker: $scope.loadingTracker}, function (data){
console.log(data)
$scope.loadedHotelDetails.push(index)
})
})
angular.module('weather', [])
.factory('weather', function($http) {
var weather = {};
weather.get = function(params, callback) {
$http.get('/php/weather.php', {params: {tracker: params.tracker, page: params.page}}).success(function(data) {
callback(data);
});
};
return weather;
});
I've never used this module, but from the examples on github, I think you're supposed to call it like this in weather:
weather.get = function(params, callback) {
$http.get('/php/weather.php', {tracker: params.tracker, page: params.page}).success(function(data) {
callback(data);
});
};
Got it sorted, this is the code I needed:
.factory('weather', function($http) {
var weather = {};
weather.get = function(params) {
return $http.get('/php/weather.php', {tracker: params.tracker, page: params.page});
};
return weather;
});

Updating ng-show from within .then()

I have a loader that I show while an async service call is completed, and simply want to hide the loader when complete. Here is my controller:
app.controller('DataController',
function($scope, DataService) {
// UI state
$scope.loading = true;
DataService.getData({ "count": 10 }).then(function(data) {
$scope.data = data;
// UI state
$scope.loading = false; // does not update ng-view
$scope.$apply(function() { // generates error
$scope.loading = false;
});
});
});
And the view:
<div ng-controller="DataController">
<div id="container">
<div>
{{ loading }}
</div>
<div class="spinner large" ng-show="loading"></div>
<div class="data-container" ng-show="!loading">
...
</div>
</div>
</div>
Note the the {{ loading }} value gets updated properly in the view. Using the wrapping $scope.$apply() call resulted in an error:
Error: [$rootScope:inprog]
UPDATE
As this might be promise-related, here's the promise generating getData() method from the DataService factory:
getData: function(params) {
var deferred = $q.defer();
APIService.data(params).then(function(data) {
deferred.resolve(data);
});
return deferred.promise;
}
And the last piece, the APIService.data() method:
data: function(params) {
var deferred = $q.defer();
$resource(endpoint + '/data/feed', {}, {
'query': {
method: 'POST',
headers: headers
}
}).query(params).$promise.then(function(data) {
deferred.resolve(data);
});
return deferred.promise;
}
I would solve this by binding the show/hide directive to the data-property in the controller. It will be the same as false if the data is undefined.
<div class="spinner large" ng-hide="data"></div>
<div class="data-container" ng-show="data">
Try to use
$scope.$evalAsync(function() {
$scope.loading = false;
});
Found the issue - as this is in a Chrome Extension, I needed to include the Angular CSS CSP file, which includes the ng-hide class definition. Including that file resulted in the code working as expected. Thanks everyone for the help. More info:
https://docs.angularjs.org/api/ng/directive/ngCsp

Categories