How to get data from service before loading the view and controller. I do like that
resolve: {
getAlbum: function(albumService){
return albumService.getAlbums();
},getAtum: function(albumService){
return albumService.getAtum();
}
}
I have one service this
.factory('albumService', ['$http', '$q'],
function albumService($http, $q) {
// interface
var service = {
albums: [],
getAlbums: getAlbums,
getAtum:getAtum
};
return service;
// implementation
function getAlbums() {
var def = $q.defer();
$http.get("data.json")
.success(function(data) {
service.albums = data;
def.resolve(data);
})
.error(function() {
def.reject("Failed to get albums");
});
return def.promise;
}
function getAtum() {
var def = $q.defer();
$http.get("data.json")
.success(function(data) {
service.albums = data;
def.resolve(data);
})
.error(function() {
def.reject("Failed to get albums");
});
return def.promise;
}
})
I need to get data from service before loading this controller and view .
.controller('PlaylistsCtrl', function($scope) {
$scope.playlists = [{
title: 'Reggae',
id: 1
}, {
title: 'Chill',
id: 2
}, {
title: 'Dubstep',
id: 3
}, {
title: 'Indie',
id: 4
}, {
title: 'Rap',
id: 5
}, {
title: 'Cowbell',
id: 6
}];
})
I am getting data from two service .I need to show loader till I get data from both service.I am using this to show loader
http://ionicframework.com/docs/api/service/$ionicLoading/
Plunker
http://plnkr.co/edit/4k7fliaYQx3teVH326cD?p=info
The resolve properties are injected automatically by ui-router right after they get resolved.
.controller('PlaylistsCtrl', function(getAlbum, getAtum) {
// getAlbum and getAtum are resolved and ready to use
})
I would use albums and atum instead of getAlbum and getAtum as it is the data itself.
You use defer wrongly. $http.get is a promise itself. also, success and error are deprecated, use then instead.
return $http.get().then();
Simplest jsbin.
If you want to show loading spinner on page until its resolve. you can do something like below.
resolve: {
apiData: "albumService",
itemDetailsData: function($q, apiData) {
console.log("Spinner on :")
var item = apiData.getAlbums();
if (item) {
console.log("Spinner Off :")
return $q.when(item);
} else {
return $q.reject();
}
}
}
In your controller you can inject itemDetailsData as a dependency.
Hope this helps
Related
i have created the custom service like this
app.service('userService', function($http,UrlService) {
return {
init: function(callback) {
$http.get(UrlService.baseUrl +'/api/users/list').then(function(user_response) {
callback(user_response);
});
}
}
})
Inside of my project main controller i have used like this to get the angular material design modal.
$scope.replyComplaint = function(user,complaint_id) {
complaint_id=user._id;
console.log(complaint_id)
$mdDialog.show({
controller: DialogCtrl,
templateUrl: 'submodules/user_management/replydialog.html',
resolve: { complaint_id : function() {return complaint_id;} },
locals: {
users: $scope.users
},
parent: angular.element(document.body),
clickOutsideToClose: true,
})
.then(function(response) {
$scope.response = response;
console.log(response);
}, function() {
//fail
});
};
created another controller for dialog as in the angular material docs as follows
function DialogCtrl($scope, $rootScope, $mdDialog, users,complaintService, UrlService, $http) {
complaintService.init(function(complaint_response) {
$scope.complaints = complaint_response.data;
$scope.getUsers();
});
$scope.getUsers = function(complaint_id) {
console.log(complaint_id);
$scope.hide = function() {
$mdDialog.hide();
};
$scope.cancel = function() {
$mdDialog.cancel();
};
$scope.replyMail = function(complaint_id) {
console.log(complaint_id);
$http.post(UrlService.baseUrl + '/api/complaints/complaint/'+complaint_id , {
complaint: "replyText"
}, $scope)
.then(function(response) {
console.log(name);
$state.reload();
}, function(response) {
console.log(name);
});
}
}
}
Now, i need to get the user_response data in DialogController. if i put console.log('$scope.users') inside of this userservice.init function, i can get the data. but not outside of it. how to get the response data outside of the userService.init function
userService.init(function(user_response) {
$scope.users = user_response.data;
}); //this is added in DialogController
Main intension is to get the user.comlaint_id in the post request of reply mail function . that user.complaint_id is a part of the user_response
Anyone please help me. Thanks
The $http.get call returns a promise, you can just use that.
app.service('userService', function($http,UrlService) {
return {
init: function(callback) {
return $http.get(UrlService.baseUrl +'/api/users/list');
}
}
});
Controller:
function Dialog($scope,$rootScope, $mdDialog,userService,UrlService,$http) {
// console.log(userService.init());
init();
function init() {
userService.init().then(function(response) {
$scope.users = response.data;
});
}
}
This also has the advantage of easier error handling:
function Dialog($scope,$rootScope, $mdDialog,userService,UrlService,$http) {
// console.log(userService.init());
init();
function init() {
userService.init().then(function(response) {
$scope.users = response.data;
}, function(error) {
// handle error
});
}
}
You should read up on angular/javascript promises and their chaining mechanism: angular promises
Here is the solution
userService.init(function(user_response) {
$scope.users = user_response.data;
$scope.init();
});
$scope.init = function() {
You can access $scope.users here
}
Call any method instead of init() in which you require $scope.users
I'm trying to unit test a function within my controller but am unable to get a $scope variable to be testable. I'm setting the variable in my controller's .then() and want to unit test to make sure this is set appropriately when it hits the .then block.
My test controller code:
function submit() {
myService.submit().then(function(responseData){
if(!responseData.errors) {
$scope.complete = true;
$scope.details = [
{
value: $scope.formattedCurrentDate
},
{
value: "$" + $scope.premium.toFixed(2)
},
];
} else {
$scope.submitError = true;
}
});
}
Where this service call goes is irrelevant. It will return JSON with action: 'submitted', 'response' : 'some response'. The .then() checks if errors are present on responseData, and if not it should set some details. These $scope.details are what I'm trying to test in my unit test below:
it('should handle submit details', function () {
var result;
var premium = 123.45;
var formattedCurrentDate = "2016-01-04";
var promise = myService.submit();
mockResponse = {
action: 'submitted',
response: 'some response'
};
var mockDetails = [
{
value: formattedCurrentDate
},
{
value: "$"+ premium.toFixed(2)
}
];
//Resolve the promise and store results
promise.then(function(res) {
result = res;
});
//Apply scope changes
$scope.$apply();
expect(mockDetails).toEqual(submitController.details);
});
I'm receiving an error that $scope.details is undefined. I'm not sure how to make the test recognize this $scope data changing within the controller.
Before each and other functions in my unit test:
function mockPromise() {
return {
then: function(callback) {
if (callback) {
callback(mockResponse);
}
}
}
}
beforeEach(function() {
mockResponse = {};
module('myApp');
module(function($provide) {
$provide.service('myService', function() {
this.submit = jasmine.createSpy('submit').and.callFake(mockPromise);
});
});
inject(function($injector) {
$q = $injector.get('$q');
$controller = $injector.get('$controller');
$scope = $injector.get('$rootScope');
myService = $injector.get('myService');
submitController = $controller('myController', { $scope: $scope, $q : $q, myService: myService});
});
});
How do I resolve the promise within my unit test so that I can $scope.$digest() and see the $scope variable change?
You should look how to test promises with jasmine
http://ng-learn.org/2014/08/Testing_Promises_with_Jasmine_Provide_Spy/
using a callFake would do what you try to mock
spyOn(myService, 'submit').and.callFake(function() {
return {
then: function(callback) { return callback(yourMock); }
};
});
This is a follow-up question to Angular-ui modal, sending data into modal controller from $http
I have the following code where I want to get data via a factory to the modal.
$scope.docSetup = function() {
var modalInstance = $modal.open({
templateUrl : '/templates/dialog/docSetup.html',
controller : 'docSetupDlgCtrl',
resolve : {
dlgData : function(){
return TagService.list($scope.publication.id);
}
}
});
modalInstance.result.then(function (dlgData) {
$log.debug(dlgData);
}, function () {
$log.debug('Modal dismissed at: ' + new Date());
});
};
And here is the factory:
app.factory("TagService", function($http, $log){
return {
list: function(selectedDoc){
$log.info("Tag service at work => list");
var httpPromise = $http.post("tags/list", { publicationId: selectedDoc });
httpPromise.then(function (response) {
$log.log(response.data);
return response.data;
}, function (error) {
$log.error(error);
});
}
}
});
The above isn't resolving any data into dlgData. The factory is producing data and if I hardcode the data object into the 'resolve' function, it passes it.
return the entire httpPromise as well:
return httpPromise.then(function (response) {
$log.log(response.data);
return response.data;
}, function (error) {
$log.error(error);
});
I am trying to set a service and want the controllers in my app get the data from the service.
I have something like
angular.module('myApp').service('testService', ['Product',
function(Product) {
var products
//Product is a $resource object to send an http request
Product$.query({
id: 123
}, function(object) {
setProducts(object);
});
var setProducts = function(object) {
products = object;
}
var getProducts = function() {
return products;
}
return {
setProducts: setProducts,
getProducts: getProducts
};
}
]);
in my another controller
angular.module('myApp').controller('productController', ['$scope', 'testService',
function($scope, testService) {
//return undefined...
console.log(testService.getProducts())
}
]);
//testService.getProducts() returns undefined.
I think the reason is because I am making $http request and it's asynchronous so the testService has no idea what the product is when the app first loads. How do I fix this issue? Thanks so much!
I use a promise "q$" to deal with asynch calls:
angular.module('myApp').service('testService', ['Product',
function(Product, $q) {
var products
var setProducts = function(object) {
products = object;
}
var getProducts = function() {
var deferred = $q.defer();
//Product is a $resource object to send an http request
Product$.query({
id: 123
}, function(object) {
setProducts(object);
deferred.resolve(object);
});
return deferred.promise;
}
return {
setProducts: setProducts,
getProducts: getProducts
};
}
]);
angular.module('myApp').controller('productController', ['$scope', 'testService',
function($scope, testService) {
//use a promise
testService.getProducts().then(function(data){
console.log(data);
},
function (error) {
console.log(error);
})
}
]);
The promise has two call backs one for complete and one for error. You can deal with the errors in your view model as needed.
I have a service which will make a call to the server and returns the data. I am binding service to a variable on scope.
Example:
Let the service be DataModelService
in the controller : $scope.data = DataModelService
in the view <div ng-repeat="value in data.persons">{{value.name}}</div>
My Code :
This is how my code looks like:
/**DataModelService**/
factory('DataModelService', [
'DataService',
function (DataService) {
var service;
service = {
changeState: function (params) {
DataService.changePersonState(params)
.then(function (response) {
service.loadData(response.data);
});
},
loadData: function (responseData) {
service.persons = responseData.persons;
}
}
return service;
}
]);
/**DataService**/
factory('DataService', ['$http',
function ($http) {
return {
changePersonState: function (params) {
return $http.post("url", params);
}
}
}
]);
/**DataController**/
.controller('DataController', ['DataModelService',
function (DataModelService) {
$scope.data = DataModelService;
}
]);
/view/
<div ng-repeat = "person in data.persons" >{{person.name}} </div>
On the view I am doing a ng-repeat on a key in data i.e. ng-repeat="value in data.persons"
and also I have an option to change the state of person to active or inactive, so whenver i make a change to the state of the person, a call is sent to the server and data is set into the Service and as it is binded to the view, it should automatically update the data. But whats happening in my case, ng-repeat is not removing old data and instead it is appending new data to the old data.
For me its not good approach to write promise callback (then) into service. Because in your case, DataModelService returns data with some delay but not promise. And we don't know when.
So the way to make it work to add basic $timeout and fetch data from service by using other method.
So my suggestion is Demo
and your fixed example: Demo2
If we will take your example, it should be like:
JS
var fessmodule = angular.module('myModule', ['ngResource']);
fessmodule.controller('fessCntrl', function ($scope, DataModelService, $timeout) {
$scope.alertSwap = function () {
DataModelService.changeState('ff');
$timeout(function(){
$scope.data = DataModelService.getResponse();
}, 10);
}
});
fessmodule.$inject = ['$scope', 'Data', '$timeout'];
/**DataModelService**/
fessmodule.factory('DataModelService', [ 'DataService',function (DataService) {
var value = [];
var service = {
changeState: function (params) {
DataService.changePersonState(params)
.then(function (response) {
value = response.persons;
});
},
getResponse : function(){
return value;
}
}
return service;
}
]);
/**DataService**/
fessmodule.factory('DataService', ['$q',function ($q) {
var data = { // dummy
persons: [{
name: "Bob"
}, {
name: "Mark"
}, {
name: "Kelly"
}]
};
var factory = {
changePersonState: function (selectedSubject) {
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
}
return factory;
} //function
]);