On my app, I need to recover data (json) by making multiples validations using http requests before all my app starts. So my problem is that I'm using angular.run() to make all the http requests and resolving all of the validations with promises.
The problem is, not all of my promises are executed before my app is started.
part of my code is:
appModule.run(configRun);
configRun.$inject = [
'$http', '$rootScope', 'gettextCatalog', 'ipLoadDataService',
'webStorageService', 'ipDataSetParserService'];
function configRun($http, $rootScope, gettextCatalog, ipLoadDataSrv, webStrSrv, dataSetParser) {
webStrSrv.clear();
ipLoadDataSrv.getHeadDataSet2()
.then(function (responseHead) {
if (ipLoadDataSrv.updatedDataSet2(responseHead.headers["last-modified"])) {
//save into localstorage
webStrSrv.clear();
webStrSrv.setItem("last-modified", { date: responseHead.headers["last-modified"] });
ipLoadDataSrv.getDataSet2()
.then(function (responseData) {
$rootScope.cabecera = responseData;
})
}
})
}
// LoadDataService
appModule.factory('ipLoadDataService', loadDataService);
loadDataService.$inject = ['$http',
'$q',
'webStorageService',
'myPrjEnvironment',
'ipDataSetParserService'];
function loadDataService($http, $q, webStoreService, myPrj, dataSetParser) {
var eventMap = [];
var ip_loadDataService = {
getHeadDataSet2: getHeadDataSet2,
requestDataSet: requestDataSet,
updatedDataSet2: updatedDataSet2,
getDataSet2: getDataSet2
};
return ip_loadDataService;
function getHeadDataSet2() {
/*HEAD*/
var deferred = $q.defer();
$http.head(myPrj.URL_DATA)
.success(function (data, status, headers, config) {
var response = [];
response.data = data;
response.headers = headers();
deferred.resolve(response);
//return deferred.promise;
}).error(function (data, status) {
deferred.reject(data);
});
return deferred.promise;
}
function getDataSet2() {
return xhr('get', [myPrj.URL_DATA]);
}
function updatedDataSet2(last_date_modified) {
//var self = this;
var dateOnWebStore = webStoreService.getItem("last-modified");
if (dateOnWebStore === null || Date.parse(dateOnWebStore.date) < Date.parse(last_date_modified))
return true;
return false;
}
function xhr(type, config) {
if (!config && angular.isArray(type)) {
config = type;
type = 'get';
}
var deferred = $q.defer();
$http[type].apply($http, config)
.success(function (data, status, headers, config) {
var response = [];
response.data = data;
response.headers = headers();
deferred.resolve(response);
})
.error(function (error) {
deferred.reject(error);
});
return deferred.promise;
}
}
Answering the question in your second post, maybe you better edit your original post with the new issue you encountered.
If what you are looking for is a way to activate a state (home.myPrjMain in your case) you can do this in various ways:
Using JS - use $state.go(). See - $State documentation
Using directive - use the ui-sref directive with the name of the required state. See - ui-sref documentation
Using regular html href (Navigate to url) - with the full address of the state you need. In your case, "/main".
I hope this was helpful
Have the UI start in an initial loading state then use ui-router to wait for the various pieces to resolve before going to the initial state.
Here is a fiddle showing how it works. Fiddle
I did two parts, one with a single fake service call using timeout and a second with a chained set of calls,.
this.slowServiceCall = function(input, delay) {
var deferred = $q.defer();
var workFinished = function () {
deferred.resolve(input);
};
$timeout(workFinished, delay);
return deferred.promise;
};
this.slowChainedServiceCall = function(input, delay) {
var deferred = $q.defer();
var workFinished = function () {
deferred.resolve(input);
};
$timeout(workFinished, delay);
var promiseChain = deferred.promise.then(function(result) {
var deferred2 = $q.defer();
$timeout(function(){
deferred2.resolve(result + ' Second Piece');
},100);
return deferred2.promise;
});
return promiseChain;
};
Related
here is my javascript code
$scope.addUser = function () {
debugger;
url = baseURL + "AddUser";
$scope.objUser = [];
$scope.objUser.push( {
"ID": '0',
"UserName": $scope.txtUserName,
"Password": $scope.txtPassword,
"Role":"Non-Admin"
});
$http.post(url,$scope.objUser[0])
.success(function (data) {
debugger;
alert("S");
window.location = "../View/Login.html";
}).error(function () {
debugger;
alert("e");
});
}
here is my server method code
[HttpPost]
public int AddUser(UserModel user)
{
//_entity.Configuration.ProxyCreationEnabled = false;
tblUser objUser = new tblUser();
objUser.UserName = user.UserName;
objUser.Password = user.Password;
objUser.Role = user.Role;
_entity.tblUsers.Add(objUser);
_entity.SaveChanges();
return objUser.ID;
}
You can use promises to get the response. this can be inside into a service and call it whenever you want to use it.
this.addUser = function (obj) {
var datosRecu = null;
var deferred = $q.defer();
var uri = baseUrl + 'addUser';
$http({
url: uri,
method: 'post',
data: angular.toJson(obj)
}).then(function successCallback(response) {
datosRecu = response;
deferred.resolve(datosRecu);
}, function errorCallback(response) {
datosRecu = response;
deferred.resolve(datosRecu);
});
return deferred.promise;
};
Also .error and .success are deprecated.
PD: the parameter data: inside the $http correspond to the body. if you want to send parameters you should use params:{}
EDIT:
Here i leave you a link how promises work. Angular promises
Basically this helps to process data asynchronously
the example above can be used inside a service like this
myApp.service('myService', function($q, $http){
// here your services....
});
the service can be injected inside to any controller to provide the data that what you want, inside of your functions
myApp.controller('myController', function($scope, myService){
$scope.list = function(){
$promise = myService.getAll(); // this will be the name of your function inside your servive
$promise.then(function(data){
console.log(data); //here you can se your promise with data like status and messages from the server.
});
};
});
Hope it helps.
I have this data
{
"config": {
"RESTAPIURL": "http://myserver/myrestsite"
}
}
and I have this factory that reads that data
'use strict';
angular.module('myApp').factory('api',
["$http", "$q",
function ($http, $q) {
function _getConfiguration() {
var deferred = $q.defer();
$http.get('/scripts/constants/config.json')
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject(data, status);
});
return deferred.promise;
}
function _restApiUrl() {
// this doesn't work either. _getConfiguration() doesn't resolve here.
return _getConfiguration().RESTAPIURL + '/api/';
}
return {
URL: _restApiUrl
}
}
]
);
Then to use it
'use strict';
angular.module('myApp').factory('AuthService', function ($http, $q, api,NotificationService) {
function _get(creds) {
var deferred = $q.defer();
$http({method: 'GET', url: api.URL() + api.AUTH, headers: {
'Authorization': 'Basic '+creds}
})
.success(function (data, status, results, headers) {
deferred.resolve(results);
})
.error(function (data, status) {
NotificationService.redirect(status);
deferred.reject(data, status);
});
return deferred.promise;
}
return {
get:_get
};
});
So when I'm using it I am doing api.URL() and it's not working.
It used to be hard coded URL so to call it used to be api.URL. I really don't want to go through the whole app and convert everything to api.URL().then(...). That would suck.
So how can I nail down this value as a "property" instead of an asynchronous promise that has to be called over and over?
Call it once, fine. Get the value. Put it somewhere. Use the value. Don't ever call the $http again after that.
EDIT
This is turning up to be one of the most successful questions I've ever asked, and I am gratefully going through each answer in turn. Thank each one of you.
Adding a bit to what #ThinkingMedia was saying in the comment, with ui-router when defining controllers you can add a resolve parameter.
In it you can specify some promises that have to resolve before the controller is instantiated, thus you are always sure that the config object is available to the controller or other services that the controller is using.
You can also have parent/child controllers in ui-router so you could have a RootController that resolves the config object and all other controllers inheriting from RootController
.state('root', {
abstract: true,
template: '<ui-view></ui-view>',
controller: 'RootController',
resolve:{
config: ['api', function(api){
return api.initialize();
}
}
});
and your api factory:
angular.module('myApp').factory('api',
["$http", "$q",
function ($http, $q) {
var _configObject = null;
function initialize() {
return $http.get('/scripts/constants/config.json')
.then(function (data) {
_configObject = data;
return data;
});
}
// you can call this in other services to get the config object. No need to initialize again
function getConfig() {
return _configObject;
}
return {
initialize: initialize,
getConfig: getConfig
}
}
]
);
I would pass a callback to the getURL method, and save the URL when it returns. Then I would attach any subsequent requests to that callback. Here I am assuming that you are doing something similar with api.AUTH that you don't have a reference to in your code.
Pass a callback to the getURL method in the api service.
angular.module('myApp').factory('api', ["$http", "$q",
function ($http, $q) {
function _getConfiguration() {
var deferred = $q.defer();
$http.get('/scripts/constants/config.json')
.success(function (data) {
deferred.resolve(data);
})
.error(function (data, status) {
deferred.reject(data, status);
});
return deferred.promise;
}
return {
getURL: function (cb) {
var that = this;
if (that.URL) {
return cb(that.URL);
}
_.getConfiguration().then(function (data) {
that.URL = data.config.RESTAPIURL + "/api";
cb(that.URL);
});
}
}
}]);
And in your AuthService, wrap your _get inside a callback like this:
angular.module('myApp').factory('AuthService', function ($http, $q, api, NotificationService) {
function _get(creds) {
var deferred = $q.defer();
var getCallback = function (url) {
$http({
method: 'GET',
url: url + api.AUTH,
headers: {
'Authorization': 'Basic ' + creds
}
})
.success(function (data, status, results, headers) {
deferred.resolve(results);
})
.error(function (data, status) {
NotificationService.redirect(status);
deferred.reject(data, status);
});
};
api.getURL(getCallback);
return deferred.promise;
}
return {
get: _get
};
});
Why don't you initialize the factory when the app is loading and put the variable onto another property? Something like this:
angular.module('myApp').factory('api', ["$http", "$q",
function ($http, $q) {
// store URL in a variable within the factory
var _URL;
function _initFactory() {
var deferred = $q.defer();
$http.get('/scripts/constants/config.json')
.success(function (data) {
// Set your variable after the data is received
_URL = data.RESTAPIURL;
deferred.resolve(data);
});
return deferred.promise;
}
function getURL() {
return _URL;
}
return {
initFactory: _initFactory,
URL: getURL
}
}
]
);
// While the app is initializing a main controller, or w/e you may do, run initFactory
//...
api.initFactory().then(
// may not need to do this if the URL isn't used during other initialization
)
//...
// then to use the variable later
function _get(creds) {
var deferred = $q.defer();
$http({method: 'GET', url: api.URL + api.AUTH, headers: {
'Authorization': 'Basic '+creds}
})
.success(function (data, status, results, headers) {
deferred.resolve(results);
})
return deferred.promise;
}
I see you haven't used any $resource's here, but I'm hoping you have a good understanding of them:
in factories/delay-resource.js:
'use strict'
angular.module('myApp').factory('delayResource', ['$resource', '$q',
function($resource, $q){
var _methods = ['query', 'get', 'delete', 'remove', 'save'];
var shallowClearAndCopy = function(src, dst) {
dst = dst || {};
angular.forEach(dst, function(value, key){
delete dst[key];
});
for (var key in src) {
if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
dst[key] = src[key];
}
}
return dst;
}
var delayResourceFactory = function(baseUrlPromise, url, paramDefaults){
var _baseUrlPromise = baseUrlPromise,
_url = url,
_paramDefaults = paramDefaults;
var DelayResource = function(value){
shallowClearAndCopy(value || {}, this);
};
_methods.forEach(function(method){
DelayResource[method] = function(params, successCB, errCB, progressCB){
if (angular.isFunction(params)) {
progressCB = successCB;
errCB = errHandlers;
successCB = params;
errHandlers = params = null;
}
else if (!params || angular.isFunction(params)){
progressCB = errCB;
errCB = successCB;
successCB = errHandlers;
params = {};
}
var _makeResultResource = function(url){
var promise = $resource(url, _paramDefaults)[method](params);
(promise.$promise || promise).then(
function successHandler(){
var data = arguments[0];
if (isInstance){
if (angular.isArray(data))
for (var i = 0; i < data.length; i++)
data[i] = new DelayResource(data[i])
else if (angular.isObject(data))
data = new DelayResource(data)
}
successCB.apply(successCB, arguments)
resultDelay.resolve.apply(resultDelay.resolve, arguments)
},
function(err){
errCB.apply(errCB, arguments)
resultDelay.reject.apply(resultDelay.reject, args)
},
function(){
progressCB.apply(progressCB, arguments)
resultDelay.notify.apply(resultDelay.notify, arguments)
}
)
}
var isInstance = this instanceof DelayResource,
resultDelay = $q.defer();
if (!angular.isString(_baseUrlPromise) && angular.isFunction(_baseUrlPromise.then))
_baseUrlPromise.then(
function successCb(apiObj){
_makeResultResource(apiObj.RESTAPIURL + _url)
},
function successCb(){
throw 'ERROR - ' + JSON.stringify(arguments, null, 4)
})
else
_makeResultResource(_baseUrlPromise.RESTAPIURL + _url);
return resultDelay.promise;
};
DelayResource.prototype['$' + method] = function(){
var value = DelayResource[method].apply(DelayResource[method], arguments);
return value.$promise || value;
}
});
return DelayResource;
}
return delayResourceFactory;
}]);
This will be the base factory that all requests to that REST API server will go through.
Then we need a factories/api-resource.js:
angular.module('myApp').factory('apiResource', ['delayResource', 'api', function (delayResource, api) {
return function (url, params) {
return delayResource(api.URL(), url, params);
};
}])
Now all factories created will just have to call the apiResource to get a handle on a resource that will communicate with the REST API
Then in a file like factories/account-factory.js
angular.module('myApp').factory('AuthRoute', ['apiResource', 'api', function (apiResource, api) {
return apiResource(api.AUTH);
}]);
Now in factories/auth-service.js:
'use strict';
angular.module('myApp').factory('AuthService', ['$q', 'AuthRoute', 'NotificationService', function ($q, AuthRoute, api, NotificationService) {
function _get(creds) {
var deferred = $q.defer();
AuthRoute.get()
.then(
function successCb(results){
deferred.resolve(results);
},
function errCb(){
// cant remember what comes into this function
// but handle your error appropriately here
//NotificationService.redirect(status);
//deferred.reject(data, status);
}
);
return deferred.promise;
}
return {
get:_get
};
}]);
As you can imagine, I haven't been able to test it yet, but this is the basis. I'm going to try create a scenario that will allow me to test this. In the mean time, feel free to ask questions or point out mistakes made
Late Addition
Forgot to add this:
'use strict';
angular.module('myApp').factory('api', ["$http", "$q", function ($http, $q) {
var restApiObj,
promise;
function _getConfiguration() {
if (restApiObj)
return restApiObj;
if (promise)
return promise;
promise = $http.get('/scripts/constants/config.json')
.then(function (data) {
restApiObj = data;
promise = null;
return data;
},
function (data, status) {
restApiObj = null;
promise = null;
});
return promise;
}
return {
URL: _getConfiguration
}
}]);
Continuing with the ui-router scenario
.state('member-list', {
url: '/members?limit=&skip='
templateUrl: '/views/members/list.html',
controller: 'MemberListCtrl',
resolve:{
members: ['$stateParams', 'MembersLoader', function($stateParams,MembersLoader){
return MembersLoader({skip: $stateParams.skip || 0, limit: $stateParams.limit || 10});
}
}
});
factory
.factory('MemberRoute', ['apiResource', function(apiResource){
return apiResource('/members/:id', { id: '#id' });
}])
.factory('MembersLoader', ['MembersRoute', function(MembersRoute){
return function(params){
return MemberRoute.query(params);
};
}])
.factory('MemberFollowRoute', ['apiResource', 'api', function(apiResource, api){
return apiResource(api.FOLLOW_MEMBER, { id: '#id' });
}])
controller
.controller('MemberListCtrl', ['$scope', 'members', 'MemberRoute', 'MemberFollowRoute', function($scope, members, MemberRoute, MemberFollowRoute){
$scope.members = members;
$scope.followMember = function(memberId){
MemberFollowRoute.save(
{ id: memberId },
function successCb(){
//Handle your success, possibly with notificationService
},
function errCb(){
// error, something happened that doesn't allow you to follow memberId
//handle this, possibly with notificationService
}
)
};
$scope.unfollowMember = function(memberId){
MemberFollowRoute.delete(
{ id: memberId },
function successCb(){
//Handle your success, possibly with notificationService
},
function errCb(){
// error, something happened that doesn't allow you to unfollow memberId
//handle this, possibly with notificationService
}
)
};
}]);
With all this code above, you will never need to do any sort of initialization on app start, or in some abstract root state. If you were to destroy your API config every 5 mins, there would be no need to manually re-initialize that object and hope that something isn't busy or in need of it while you fetch the config again.
Also, if you look at MembersRoute factory, the apiResource abstracts/obscures the api.URL() that you were hoping not to have to change everywhere. So now, you just provide the url that you want to make your request to, (eg: /members/:id or api.AUTH) and never have to worry about api.URL() again :)
I'm trying to make couple of HTTP requests, one inside another, and I'm having a trouble restructuring my JSON object.
I have a factory function, first of all i'm trying to get all the teams, each team has an Id, and then i'm getting all the news for each team with the id related, and putting that news in the first JSON object.
but this is not working !
.factory('teamsFactory', function ($http,CacheFactory,LocaleManager,$q)
{
teams.Getteams= function()
{
var zis=this;
var promise=$http({method:"GET",url:"http://www.myserver/teams"});
promise.then(function(response){
for (var i=0;i<response.data.length;i++) {
zis.getTeamsNews(response.data[i].idTeam).then(function(newsresponse){
response.data[i].news=newsresponse.data;
});
}
},alert('error'));
return promise;
}
teams.getTeamsNews= function(idTeam)
{
var promise=$http({method:"GET",url:"http://www.myserver.com/news?team="+idTeam});
promise.then(null,alert('error'));
return promise;
}
});
I think it's better to push all the $http promises into an array and then use $q.all() to group them together rather than calling them each individually in a loop. Try this:
Note I had to move some of your functions around and create dummy data etc. so you will have to alter it slightly to fit your app.
DEMO
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, teamsFactory) {
$scope.name = 'World';
teamsFactory.Getteams()
.then(function(data){
$scope.teamsData = data;
});
});
app.factory('teamsFactory', function ($http, $q){
var teams = {};
teams.getFavoriteTeamsNews = function(teamId){
return $http
.get('news.json')
.then(function(response){
console.log('gtTeamNews response', response);
return response.data[teamId];
})
}
teams.Getteams = function(){
var zis = this,
httpConfig = {
method : "GET",
url : "teams.json"
};
return $http(httpConfig)
.then(function(response){
var teamId, promise,
requests = [];
for(var i = 0; i <response.data.length; i++){
teamId = response.data[i].idTeam;
promise = teams.getFavoriteTeamsNews(teamId);
requests.push(promise);
}
return $q
.all(requests)
.then(function(responses){
angular.forEach(responses, function(newsresponse, index){
response.data[index].news = newsresponse;
});
return response.data;
});
})
.catch(function(error){
console.log('error', error);
});
}
return teams;
// teams.TeamsNews= function(idTeam){
// return $http({method:"GET",url:"http://www.myserver.com/news?team="+idTeam})
// .catch(function(){
// alert('error')
// });
// }
});
update
You could also re-factor the above to take advantage of promise chaining which makes it much cleaner in my opinion. This should give the same output but is more 'flat', i.e. has less indentation/callback hell:
DEMO2
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, teamsFactory) {
$scope.name = 'World';
teamsFactory.Getteams()
.then(function(data){
$scope.teamsData = data;
});
});
app.factory('teamsFactory', function ($http, $q){
var responseData,
teams = {};
teams.getFavoriteTeamsNews = function(teamId){
return $http
.get('news.json')
.then(function(response){
console.log('gtTeamNews response', response);
return response.data[teamId];
})
}
teams.Getteams = function(){
var zis = this,
httpConfig = {
method : "GET",
url : "teams.json"
};
return $http(httpConfig)
.then(function(response){
var teamId, promise,
requests = [];
responseData = response.data;
for(var i = 0; i < responseData.length; i++){
teamId = responseData[i].idTeam;
promise = teams.getFavoriteTeamsNews(teamId);
requests.push(promise);
}
return $q.all(requests);
})
.then(function(responses){
angular.forEach(responses, function(newsresponse, index){
responseData[index].news = newsresponse;
});
return responseData;
})
.catch(function(error){
console.log('error', error);
});
}
return teams;
});
eventually something like that .. this is raw solution .. could be enhanced with caching ...
var module = angular.module('myapp', []);
module.factory('teamsFactory', function ($http,CacheFactory,LocaleManager,$q)
{
function ExtractTeamFromData(data){
// TODO
console.log("TODO: Exctract teams from data ...");
}
function FindTeamById(teams, tgeamId){
// TODO
console.log("TODO: Find team by id ...");
}
function ExtractNewsFromData(data){
// TODO
console.log("TODO: Exctract news from data ...");
}
var GetTeams= function()
{
var zis=this;
var promise = $http({method:"GET",url:"http://www.myserver/teams"});
var successCallback = function(data, status, headers, config) {
var teams = ExtractTeamFromData(data);
return teams;
};
var errorCallback = function(reason, status, headers, config) {
console.error("Some error occured: " + reason);
return {
'errorMessage': reason
};
}
promise.then(successCallback,errorCallback);
return promise;
}
var GetTeam = function(idTeam)
{
var promise = GetTeams();
var successTeamsCallback = function(teams, status, headers, config) {
return FindTeamById(teams, tgeamId);
};
var errorTeamsCallback = function(reason, status, headers, config) {
console.error("Some error occured: " + reason);
return {
'errorMessage': reason
};
}
promise.then(successTeamsCallback,errorTeamsCallback);
return promise;
}
var GetTeamsNews = function(idTeam){
var promise = GetTeam(idTeam);
var successTeamCallback = function(team, status, headers, config) {
var newsPromise = $http({method:"GET",url:"http://www.myserver.com/news?team="+idTeam});
var successNewsCallback = function(data, status, headers, config) {
var news = ExtractNewsFromData(data);
return news;
};
var errorNewsCallback = function(reason, status, headers, config) {
console.error("Some error occured: " + reason);
return {
'errorMessage': reason
};
}
newsPromise.then(successNewsCallback,errorNewsCallback);
return newsPromise;
};
var errorTeamCallback = function(reason, status, headers, config) {
console.error("Some error occured: " + reason);
return {
'errorMessage': reason
};
}
promise.then(successTeamCallback,errorTeamCallback);
return promise;
}
return {
GetTeams: GetTeams,
GetTeam: GetTeam,
GetTeamsNews: GetTeamsNews
};
});
You need to create a promise of your own, and resolve it when done, this way :
return $q(function(resolve, reject) {
$http({method:"GET",url:"http://www.myserver/teams"}).then(function(response){
var promises = [];
for (var i=0;i<response.data.length;i++) {
promises.push(zis.getFavoriteTeamsNews(response.data[i].idTeam)).then(function(newsresponse){
response.data[i].news=newsresponse.data;
});
}
$q.all(promises).then(function(){
resolve(response);
});
});
for (var i=0;i<response.data.length;i++) {
zis.getFavoriteTeamsNews(response.data[i].idTeam).then(function(newsresponse){
response.data[i].news=newsresponse.data;
})
});
As soon as Html page gets loaded, it calls SuperCategoryController, where i am assigning supercategories to $scope variable.
$scope.SuperCategories = SuperCategoryService.GetSuperCategories();
But as this controller is depends on service, which in turn calls the http request. so at the time pf assignment http request is not completed. so $scope.SuperCategories is getting assiged to undefined.
sampleApp.service('SuperCategoryService', ['$http', function ($http){
var URL = 'http://localhost/cgi-bin/superCategory.pl';
var SuperCategories;
$http({
method: 'POST',
url: URL,
data: "action=GET",
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).
success(function (data) {
alert (data);
if (data != null || data != 'undefined') {
SuperCategories = data;
}
})
.error(function (error) {
alert (error.message);
//$scope.status = 'Unable to retrieve super categories' + error.message;
});
//simply returns the SuperCategories list
this.GetSuperCategories = function () {
//alert (SuperCategories);
return SuperCategories;
}
}]);
sampleApp.controller('SuperCategoryController', ['$scope', 'SuperCategoryService', function ($scope, SuperCategoryService){
$scope.SuperCategories = SuperCategoryService.GetSuperCategories();
$scope.LoadSuperCategoryMapping = function()
{
alert ($scope.SelectedSuperCategory.id);
}
}]);
How to solve this problem in proper way.
I haven't tried this code myself but I would approach a solution using factory and a promise to make sure the data has been loaded. Something along these lines:
sampleApp.factory('SuperCategoryService', ['$http', function ($http){
return {
GetSuperCategories: function () {
var URL = 'http://localhost/cgi-bin/superCategory.pl';
return $http.get(URL);
}
}
}]);
sampleApp.controller('SuperCategoryController', ['$scope', 'SuperCategoryService', function ($scope, SuperCategoryService){
$scope.SuperCategories = function() {
SuperCategoryService.GetSuperCategories()
.then(function(d) {
if (d.data != undefined) {
// Your data should be loaded here
console.log(d.data);
$scope.SuperCategories = d.data;
}
})
.error(function(data, status) {
// Errors here
});
}
}]);
I have an http-method that gets some data from a google spreadsheet. I want to add this to the $scope so I can output it in the DOM. Later I might make a timed loop of this so that the $scope get's updated every 5 seconds or so.
I currently run the code in app.run:
angular.module('spreadsheet2angular', []).
run(function($http){
$http({method: 'GET', url: 'http://cors.io/spreadsheets.google.com/feeds/cells/0Aq_23rNPzvODdFlBOFRYWlQwUFBtcXlGamhQeU9Canc/od6/public/values?alt=json'}).
success(function(data, status, headers, config) {
var entries = data.feed.entry;
var phraces = [];
entries.forEach(function(entry){
var cell = entry.gs$cell;
if(!phraces[cell.row]){
phraces[cell.row] = {};
}
if(cell.col == 1)
{
phraces[cell.row].name = cell.$t;
}
else if(cell.col == 2)
{
phraces[cell.row].value = cell.$t;
}
});
phraces.forEach(function(phrace){
console.log(phrace);
});
}).
error(function(data, status, headers, config) {
console.log('error');
});
});
I'm new to angular, is this the best place to run it? I would like to run it as something that is easily reusable in different projects.
I think from what you've explained, a service would be perfect. Build it out then inject it in your controller. You can then call/use that service object whenever you would like.
I would use service/factory that returns promise. So we call async service method, get back promise and parse response into controller.
If you think to use the same call in the future, you can write generic method.
By the same way, if you are going to parse response by the same way in the future, the part of logic I would put into the service as well and wrap with $q . So the response still will be promise.
And this is an example I use that might help you to understand what I'm meaning:
app.service('apiService', ['$http', '$q', '$rootScope',
function($http, $q, $rootScope) {
var request = function(method, data) {
var deferred = $q.defer();
var configHttp = {
method: 'POST',
url: config.api + '/' + method
};
if (data !== undefined) {
configHttp.data = data;
}
$http(configHttp).success(function(data, status, headers) {
if (data.error === undefined) {
deferred.resolve(data);
} else {
deferred.reject(data);
}
}).error(function(data, status, headers) {
deferred.reject(data);
});
return deferred.promise;
}
return {
getItem: function() {
return request('get_item');
},
getItemByParams: function(id) {
return request('get_item_by_params', {id: id});
}
};
}
]);