So I have created a Notifications service in AngularJS and well I'm not getting any meaning full data back in my $scope.Notifications variable.
I can see the service is being called and running at the correct interval, and the correct data is being returned from the API:
[{"id":1,"user_id":1,"content":"You have new mail: Test","read":null,"type":"mail","deleted_at":null,"created_at":"2015-06-23 20:16:38","updated_at":"2015-06-23 20:16:38"},{"id":2,"user_id":1,"content":"You have new mail: Test","read":null,"type":"mail","deleted_at":null,"created_at":"2015-06-23 20:16:38","updated_at":"2015-06-23 20:16:38"},{"id":3,"user_id":1,"content":"You have new mail: Test","read":null,"type":"mail","deleted_at":null,"created_at":"2015-06-23 20:16:38","updated_at":"2015-06-23 20:16:38"}]
Essentially, all I need from this is a simple array of the users notifications.
Here is my service:
app.services.Notifications = ['$http', '$timeout', function($http, $timeout){
var timeoutId;
var notificationService = this;
function checkForNotifications(){
console.log('checking')
return $http.get('/api/notifications')
.then(function(res){
return res.data.filter(function(notification){
return notification.unread === true;
})
})
.then(function(unreadNotifications){
//fake for effect
notificationService.count = Math.floor(Math.random() * (100 - 1)) + 1;
//notificationService.count = unreadNotifications.length;
})
.then(waitAndCheck)
}
function waitAndCheck(){
return $timeout(function(){
checkForNotifications()
},5000);
}
return {
Notifications: waitAndCheck()
}
}];
And my controller:
app.controllers.notificationsController = ['$scope', 'Notifications', function($scope, Notifications) {
$scope.Notifications = Notifications;
}];
If I console log $scope.Notifications in the controller I being return this:
Object {Notifications: d}Notifications: d$$state: Objectstatus: 1value: undefined__proto__: Object$$timeoutId: 1__proto__: Object__proto__: Object
Set your $scope.Notifications = Notifications.Notifications;
app.controllers.notificationsController = ['$scope', 'Notifications', function($scope, Notifications) {
$scope.Notifications = Notifications.Notifications;
}];
Currently the thing which you are getting in console is nothing but a promise object which is conceptually correct. If you want the data from it then you use resolve that promise chain using .then function on Notification service.
Notifications.Notifications.then(function(data){
$scope.Notifications = data;
})
Related
(function () {
angular.module("app").controller('DashboardController', ['$q', 'dashboardService', function ($scope, $q,dashboardService) {
var DashboardController = this;
dashboardService.loadFromServer(DashboardController );
console.log("DashboardController ", DashboardController);
}])
})();
angular.module("app").service('dashboardService', ['$http', '$q', function ($http, $q) {
return {
loadFromServer: function (controller) {
var getDashboardEntries = $http.get('http://someUrl');
var getEmailData = $http.get('http://someOtherUrl');
var getSidebarData = $http.get('http://yetAnotherUrl');
return $q.all([getDashboardEntries, getSidebarData, getEmailData])
.then(function (results) {
controller.dashboardData = results[0].data;
controller.chartData = results[1].data;
controller.emailData = results[2].data;
});
},
};
}]);
1.The service returns the three bits of data and this is the results when logged using:
console.log("DashboardController ", DashboardController);
When I try to drill down on the data in this manner it logs "undefined"
console.log("DashboardController "DashboardController.dashboardData);
console.log("DashboardController "DashboardController.chartData);
console.log("DashboardController "DashboardController.emailData);
Do you realize that console.log is executed right after invoking loadFromServer before the server has chance to respond and promise resolves? The actual order is:
loadFromServer
console.log
promise success method - where you actually have your data
Change your controller's code to this:
dashboardService.loadFromServer(DashboardController ).then(function() {
console.log("DashboardController ", DashboardController);
});
What would be even better is to construct some object from parts of responses and assign it in the controller itself - not the service. In current implementation if you wanted to have another controller then service would assign response parts to same fields. I'd propose sth like this:
return $q.all([getDashboardEntries, getSidebarData, getEmailData])
.then(function (results) {
var data = {
dashboardData = results[0].data;
chartData = results[1].data;
emailData = results[2].data;
};
return data;
});
and then in controller:
dashboardService.loadFromServer().then(function(data) {
DashboardController.dashboardData = data.dashboardData;
DashboardController.chartData = data.chartData;
DashboardController.emailData = data.emailData;
});
In this solution the controller decides what to do with data, not the other way around.
I have a service which get data from a file(path is given by the controller) and return a promise - then another service that create a object with properties using the returned data from the last service.
My problems are:
The getDataService runs before controller so it has no path from which to fetch data => nothing in return(an error)
Provider 'GetDataService' must return a value from $get factory method.
I need to keep this structure because I'll have more controllers with different paths to give
I'm also opened to other solutions but I need to make sure that datas are loaded before the template get populated. I've tried to call SetProperties service first with getData service into it - but still getData.js is executed first
getdata Service
angular.module('myApp').factory('GetDataService',['$http', function($http) {
var getData = function(path){
return $http.get(path).then(function(result) {
return result.data;
});
};
}]);
setProperties service
angular.module('myApp').service('PageProperties',['$http', function($http) {
this.setProps = function(page, data) {
some code here
var properties = {
isCenterActive : isActive_val,
//header elements
titleClass : page,
title : data.titles[page],
//footer elements
leftLink : leftLink_val,
leftFooterClass: leftLink_val,
leftTitle: data.titles[leftLink_val],
centerLink : centerLink_val,
centerFooterClass: data.titles[centerLink_val],
centerTitle : centerTitle_val,
rightLink : rightLink_val,
rightFooterClass: rightLink_val ,
rightTitle : data.titles[rightLink_val],
}
return properties;
}
}]);
controller
angular.module('myApp', [])
.controller('meniuController', ['$http', '$stateParams', '$scope', 'GetDataService', 'PageProperties',
function($http, $stateParams, $scope, GetDataService, PageProperties){
var page = "meniu";
$scope.language = $stateParams.lang;
var path = '_global/views/services/json/' + $stateParams.lang + '_data.json';
/*PageProperties.setProps(page, path).then(function(data){
//some code here
});*/
GetDataService.getData(path).then(function(data){
$scope.props = PageProperties.setProps(page, data);
}).catch(function(){
$scope.error = 'Unable to get data';
});
}])
Thanks in advance!!
The error says your GetDataService provider (defined as factory) doesn't return anything
angular.module('myApp').factory('GetDataService',['$http', function($http) {
var getData = function(path){
return $http.get(path).then(function(result) {
return result.data;
});
};
// you need to actually return something
return { getData: getData };
}]);
Then you can make your PageProperties use GetDataService
angular
.module('myApp')
.service('PageProperties',['GetDataService', function(GetDataService) {
this.getProperties = function(path) {
return GetDataService.getData(path).then(/*transform here*/)
}
I'm new in angularJS and I got a small problem which is :
(i'll explain some details)
I have a SQL database which is deployed in Azure and I get the data from web services.
when I want to retrieve data from the database and expose it in the view , it works.
this is the controller :
var app = angular.module('ngdemoApp.controllers', []);
app.controller('CustomerViewCtrl', ['$scope', '$routeParams', 'ShowCustomerFactory','LikeProfilCustomerFactory','ShowManagerFactory',
function ($scope, $routeParams, ShowCustomerFactory,LikeProfilCustomerFactory,ShowManagerFactory) {
$scope.incrementLikeProfil = function (id) { LikeProfilCustomerFactory.likeProfil({id:$scope.customer.Id});
$scope.customer = ShowCustomerFactory.show({id: $routeParams.id});
}
$scope.customer = ShowCustomerFactory.show({id: $routeParams.id});
}]);
notice that the customer is in the database so it has properties in other word if I do {{customer.Id}} this expression shows me the value in the view.
However, when I want to use the $scope.customer in the controller like this
app.controller('CustomerViewCtrl', ['$scope', '$routeParams', 'ShowCustomerFactory','LikeProfilCustomerFactory','ShowManagerFactory',
function ($scope, $routeParams, ShowCustomerFactory,LikeProfilCustomerFactory,ShowManagerFactory) {
$scope.incrementLikeProfil = function (id) {
LikeProfilCustomerFactory.likeProfil({id:$scope.customer.Id});
$scope.customer = ShowCustomerFactory.show({id: $routeParams.id});
}
$scope.customer = ShowCustomerFactory.show({id: $routeParams.id});
$scope.test = $scope.customer.Id;
}]);
the $scope.test cannot be filled by $scope.customer.Id, at the same time the $scope.customer is filled and the view can display the value of customer but when I want to display the $scope.test in the view, i didn't get any responce.
Is there any solution ? Thank you
$scope.customer = ShowCustomerFactory.show({id: $routeParams.id});
If the above statement is making a service request and fetching data from server. This will be async and won't be available.
But in the next statement itself, you are setting
$scope.test = $scope.customer.Id;
At this point of time, $scope.customer may be undefined. That's why you're not getting the value.
You must put this statement in the then() function of promise $scope.test = $scope.customer.Id;
So in your service, return promise using $http or $q. And in your controller:
ShowCustomerFactory.show({id: $routeParams.id}).then(function(data) {
$scope.customer = data;
$scope.test = $scope.customer.id;
});
Another workaround would be :
Initially set
$scope.customer = {};
Also here is my service I use $resource :
services.factory('ShowCustomerFactory', function ($resource) {
return $resource(url + '/customerService/getCustomer?id=:id', {}, {
show: { method: 'GET',params: {id: '#id'} }
});
});
I have a basic data Service which will be used across Controllers. But I'm having an issue grabbing some data that's been added via $http.
Service:
angular.module('core').service('FormService', ['$http', function($http) {
var _this = this;
_this.dropdownData = {
contactTimes: ['Anytime','Morning','Afternoon','Evening'],
industries: {},
};
$http.get('/json').success(function(resp){
_this.dropdownData.industries = resp.industries;
});
}]);
Controller:
angular.module('core').controller('SignupController', ['$scope', '$http', '$state', 'FormService', function($scope, $http, $state, FormService) {
console.log(FormService.dropdownData); // Shows full object incl industries
console.log(FormService.dropdownData.industries); // empty object {}
}]);
How do I get FormService.dropdownData.industries in my controller?
Create a service like below
appService.factory('Service', function ($http) {
return {
getIndustries: function () {
return $http.get('/json').then(function (response) {
return response.data;
});
}
}
});
Call in controller
appCtrl.controller('personalMsgCtrl', ['$scope', 'Service', function ($scope, Service) {
$scope.Industries = Service.getIndustries();
}]);
Hope this will help
Add a method to your service and use $Http.get inside that like below
_this.getindustries = function (callback) {
return $http.get('/json').success(function(resp){
_this.dropdownData.industries = resp.industries;
callback(_this.dropdownData)
});
};
In your controller need to access it like below.
angular.module('core').controller('myController', ['$scope', 'FormService', function ($scope, FormService) {
FormService.getDropdownData(function (dropdownData) {
console.log(dropdownData); // Shows full object incl industries
console.log(dropdownData.industries); // object {}
});
} ]);
Given that your console log shows the correct object, that shows your service is functioning properly. Only one small mistake you have made here. You need to access the data attributes in your return promise.
angular.module('core').service('FormService', ['$http', function($http) {
var _this = this;
_this.dropdownData = {
contactTimes: ['Anytime','Morning','Afternoon','Evening'],
industries: {},
};
$http.get('/json').success(function(resp){
//note that this is resp.data.industries, NOT resp.industries
_this.dropdownData.industries = resp.data.industries;
});
}]);
Assuming that you're data is indeed existing and there are no problems with the server, there are quite a few possible solutions
Returning a promise
angular.module('core').service('FormService', ['$http', function($http) {
var _this = this;
_this.dropdownData = {
contactTimes: ['Anytime','Morning','Afternoon','Evening'],
industries: {},
};
_this.dropdownData.industries = $http.get('/json');
}]);
//Controller
FormService.industries
.then(function(res){
$scope.industries = res.industries
});
Resolving with routeProvider / ui-route
See: $http request before AngularJS app initialises?
You could also write a function to initialize the service when the application starts running. At the end of the day, it is about waiting for the data to be loaded by using a promise. If you never heard about promises before, inform yourself first.
The industries object will be populated at a later point in time when the $http call returns. In the meantime you can still bind to the reference in your view because you've preserved the reference using angular.copy. When the $http call returns, the view will automatically be updated.
It is also a good idea to allow users of your service to handle the event when the $http call returns. You can do this by saving the $promise object as a property of industries:
angular.module('core').service('FormService', ['$http', function($http) {
var _this = this;
_this.dropdownData = {
contactTimes: ['Anytime','Morning','Afternoon','Evening'],
industries: {},
};
_this.dropdownData.industries.$promise = $http.get('/json').then(function(resp){
// when the ansyc call returns, populate the object,
// but preserve the reference
angular.copy( resp.data.industries, _this.dropdownData.industries);
return _this.dropdownData.industries;
});
}]);
Controller
app.controller('ctrl', function($scope, FormService){
// you can bind this to the view, even though the $http call has not returned yet
// the view will update automatically since the reference was preserved
$scope.dropdownData = FormService.dropdownData;
// alternatively, you can hook into the $http call back through the $promise
FormService.dropdownData.industries.$promise.success(function(industries) {
console.log(industries);
});
});
Assuming my service is returning a promise from a $resource get, I'm wondering if this is the proper way to cache data. In this example, after hitting the back arrow and returning to the search results, I don't want to query the webserver again since I already have them. Is this the proper pattern to handle this situation? The example below is querying the Flixter (Rotten Tomatoes) Api.
Boilded down code:
Controller:
function SearchCtrl($scope, $route, $routeParams, $location, DataService) {
DataService.search($routeParams.q).then(function(data){
$scope.movies = data.movies;
});
}
Service:
angular.module('myApp.services', []).
factory('DataService', ['$q', '$rootScope', 'JsonService', function ($q, $rootScope, JsonService) {
var movie = {};
var searchResults = {};
var searchq = '';
var service = {
search: function(q) {
var d = $q.defer();
// checking search query, if is the same as the last one,
//resolve the results since we already have them and don't call service
// IS THIS THE CORRECT PATTERN
if (q==searchq) {
d.resolve(searchResults);
} else {
// returns a $resource with defined getdata
JsonService.search.movieSearch(q, 20, 1).getdata(function(data){
searchResults = data;
searchq = q;
d.resolve(searchResults);
});
}
return d.promise;
},
getSearchResults: function() {
return searchResults;
}
};
return service;
}]);
I can't provide a working example as it would expose my API key.
I've faked out the actual ajax request but I think the general idea should apply, you can see the full demo here
Here is the controller, it just executes the search and then sets the results:
myApp.controller('MyCtrl', function($scope, DataService) {
$scope.search = function(){
DataService
.search($scope.q)
.then(function(response){
$scope.fromCache = response.fromCache;
$scope.results = response.results;
});
};
});
In the DataService I am just saving results into an object keyed off the query. It is simplistic but hopefully will get you started. You could save it in html5 storage or something if you want something like that.
You will need to put in your actual ajax call here, but the principle remains.
myApp.factory('DataService', function($q){
var resultsCache = {};
return {
search: function(query){
var deferred = $q.defer();
if (resultsCache[query]) {
resultsCache[query].fromCache = true;
}
else {
resultsCache[query] = {results: [{name: 'result one'}, {name: 'result two'}]};
}
deferred.resolve(resultsCache[query]);
return deferred.promise;
}
};
});
Hope that helps