I'm trying to get a value from a URL part, into my $http getURL request. I have tried a few solutions (such as HTML5mode) but have not had success.
Here is my code:
angular.module('myapp123.products', [])
.factory('productsApi', ['$http', '$location',
function($http, $location){
var BASE_URL = 'http://stashdapp-t51va1o0.cloudapp.net/api/item/';
return {
get: getApiData
};
function getData() {
var product_id = $location.path().split("/")[3] || "Unknown"; //URL = /#/product/id/1234 <---
return $http.get(BASE_URL + product_id);
}
}]
)
.controller('productsCtrl', ['$scope', '$log', 'productsApi', 'UserService',
function($scope, $log, productsApi, UserService) {
$scope.isVisible = function(name){
return true;// return false to hide this artist's albums
};
// <====== Rewrite with accounts preferences
productsApi.getApiData()
.then(function (result) {
//console.log(JSON.stringify(result.data)) //Shows log of API incoming
$scope.products = result.data;
})
.catch(function (err) {
$log.error(err);
});
}
]);
The code in your example has a lot of syntax errors in it. Here is what it should look like, based on what I think you are going for...
angular.module('myapp123.products', [])
.config(locationConfig)
.factory('productsApi', productsApiFactory)
;
locationConfig.$inject = ['$locationProvider'];
function locationConfig($locationProvider) {
$locationProvider.html5Mode(true);
}
productsApiFactory.$inject = ['$http', '$location'];
function productsApiFactory($http, $location) {
var BASE_URL = 'http://stashdapp-t51va1o0.cloudapp.net/api/list/';
return {
get: getData
};
function getData() {
var product_id = $location.path().split("/")[3] || "Unknown";
return $http.get(BASE_URL + product_id);
}
}
In this version, the config function is correctly defined to set up html5mode and the service factory is configured to use $location each time the get() method is called.
You would use the service in a controller like this:
ExampleController.$inject = ['productsApi'];
function ExampleController(productsApi) {
productsApi.get()
.then(function onSuccess(res) {
// handle successful API call
})
.catch(function onError(err) {
// handle failed API call
})
;
}
Related
I'm new to angular and I've been told that it's better to make services do the heavy lifting for the controllers, but I'm finding it diffcult to make use of the services I've created. I've seen several questions on this but I can't find solutions.
Here's my service
(function () {
'use strict';
var office = angular.module('Office', []);
office.factory('auth', ['$http', '$localForage', '$scope', function ($http, $localForage, $scope) {
var auth = {}
auth.login = function (credentials) {
$http.post('/auth_api/login', credentials)
.then(function (data) {
$localForage.setItem('user', data.data)
},
function () {
$scope.login_error = 'Invalid Username/password'
})
}
$localForage.getItem('user').then(function (data) {
auth.isAuthenticated = !!data.id
})
return auth
}])
And here's my controller
office.controller('LoginController', ['$scope', 'auth', function ($scope, auth) {
$scope.login = auth.login($scope.user)
}])
I have created a simpler version from your code.. and its working here . check the link - fiddle
app.factory('auth', ['$http', function ($http) {
var auth = {};
auth.login = function (credentials) {
return "success";
}
return auth;
}]);
replace login function with your implemenation
Your code is correct but as you are not returning anything from the "auth" factory, you are not getting any update in the controller. Change your code as shown below to return the data from factory or any message acknowledging the login.
Factory :
(function () {
'use strict';
var office = angular.module('Office', []);
office.factory('auth', ['$http', '$localForage', '$scope', function ($http, $localForage, $scope) {
var auth = {}
auth.login = function (credentials) {
return $http.post('/auth_api/login', credentials)
.then(function (data) {
$localForage.setItem('user', data.data);
setAuthentication(true);
return data.data;
},
function (err) {
return err;
});
}
auth.setAuthentication = function (isLoggedIn){
this.isAuthenticated = isLoggedIn;
}
return auth;
}]);
Controller :
office.controller('LoginController', ['$scope', 'auth', function ($scope, auth) {
$scope.login = function (){
auth.login($scope.user).then(function (data){
$scope.userDetails = data;
}, function (err){
$scope.loginError = 'Invalid Username/password';
});
}
}]);
i have my authservice as given below ,
myApp.factory('Authentication',
['$rootScope', '$location', 'URL', '$http', '$q',
function ($rootScope, $location, URL, $http, $q) {
var myObject = {
authwithpwd: function (user) {
var dfd = $q.defer();
$http
.post('Mart2/users/login', {email: user.email, password: user.password})
.then(function (res) {
return dfd.resolve(res.data);
}, function (err) {
return dfd.reject(err.data);
});
return dfd.promise;
} //login
};
return myObject;
}]); //factory
And i'm using that service in user service as follows :
myApp.factory('UserService',
['$rootScope', '$location', 'URL', '$http', '$q', 'Authentication',
function ($rootScope, $location, URL, $http, $q, $Authentication) {
var myObject = {
login: function (user) {
$Authentication.authwithpwd(user).then(function (regUser) {
console.log(regUser);
}).catch(function (error) {
$rootScope.message = error.message;
});
},
getUserToken: function () {
return $rootScope.currentUser.apiKey;
},
isLogged: function () {
if ($rootScope.currentUser) {
return true;
} else {
return false;
}
}
//login
};
return myObject;
}]); //factory
I am very new to angular js . While writing service and calling that service from controller i have put a console debug in user service which is showing its returning object .i am getting object if i do console.log(regUser) ? any idea why ?
To get the object you need to do change your myObject declaration. Basically you need to return a promise from the login function and then write a callback to get the resolved data.
myApp.factory('UserService',
['$rootScope', '$location', 'URL','$http','$q','Authentication',
function($rootScope,$location, URL,$http,$q,$Authentication) {
var myObject = {
login: function(user) {
var defer = $q.defer();
$Authentication.authwithpwd(user).then(function(regUser) {
console.log(regUser);
defer.resolve(regUser);
}).catch(function(error) {
$rootScope.message = error.message;
defer.reject(regUser);
});
return defer.promise;
},
getUserToken:function() {
return $rootScope.currentUser.apiKey;
},
isLogged:function() {
if($rootScope.currentUser){
return true;
} else {
return false;
}
}//login
};
return myObject;
}]); //factory
To extract the object from controller or from some other service you need to write a callback
UserService.login(user)
.then(function (data) {
$scope.data = data;
}, function (error) {
$scope.error = error;
});
Also in the Authentication service you can just do a 'dfd.resolve' instead of 'return dfd.resolve'; since you are already returning the dfd.promise.
I have created a fiddler here
So i can get data from a URL if i do it from with in my controller. But if i take that and move it into a factory it doesn't work. So what am i doing wrong?
angular.module('starter.notifications', [])
.factory('Notifications', function($http) {
var link = "http://localhost:8000/notifications";
var notifications = [];
return {
getAll: function()
{
return $http.get(link).success(function(data, status, headers, config) {
notifications = data;
return notifications;
});
},
This code works if i move it into a controller, but why doesn't it work in a factory?
This is how i did it.
In the top of your app.js
angular.module('app', ['ionic', 'app.controllers', 'app.services','ngCordova'])
Let ionic knows you have an services.js by declaring it.
services.js (an http post request example)
angular.module('app.services', ['ngCordova'])
.factory('dataFactory', function($http, $cordovaGeolocation){
var dataFactory = {};
dataFactory.login = function(username, password){
var config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
var data = 'userID=' + username + '&password=' + password +'';
var httpAddressDoLogin = "http://YOURURL";
return $http.post(httpAddressDoLogin, data, config);
};
return dataFactory;
})
In your controller:
dataFactory.login(username, password).then(function(resp) {
Hope that helps.
On services.js $http.get resulting promise not object array. To make it work write like this on your services.js
angular.module('starter.services', [])
.factory('Actor', function($http) {
var actors = $http.get('http://ringkes/slim/snippets/actor').then(function(resp) {
if (resp) {
return = resp['data'];// This will produce promise, not array so can't call directly
} else {
console.error('ERR', err);
}
});
return {
all: function() {
return actors;
}
};
});
then call it on controller like this:
controller('DashCtrl', function($scope,Actor,$http) {
Actor.all().then(function(actors){ $scope.actors = Actor.all();
});
});
I want to wait for a service $http result before the controller does the rest.
I tested some hardcoded JSON for myData and it IS visible in the controller, but as soon as I try to populate myData with a $http request, the controller is not waiting for it and just walks thru the rest of the code. The network tab from Chrome webdevelopper is showing the expected result for the request.
I already have the following:
var ListerApp = angular.module('ListerApp',[
'ListerAppFilters',
'sharedFactoryApp',
'sharedServiceApp',
'ListerAppController',
'infinite-scroll',
'angular-inview',
'ngRoute'
]);
ListerApp.config(['$routeProvider', '$httpProvider', function($routeProvider, $locationProvider) {
$routeProvider
.when('/list',
{
templateUrl: '/assets/services/partials/list.html',
controller: 'ListerCtrl',
resolve : {
'sharedServiceAppData': function($sharedServices){
// sharedFactoryAppData will also be injectable in your controller, if you don't want this you could create a new promise with the $q service
return $sharedServices.promise();
}
}
}
);
}]);
angular.module('sharedServiceApp', []).service('$sharedServices', ['$http', '$rootScope', '$q', function($http, $rootScope, $q) {
var myData = null;
return {
promise : function () {
if (!myData) {
$http({method : 'GET', url : '/shop/api/json', params : {
end : $rootScope.endmarkerSyncDataset,
page : 1,
per_page : $rootScope.itemsPerPage
}
}).success(function (data) {
myData = data.data_set;
//deferred.resolve(data.data_set);
});
// I allready tested this and this is OK: myData = {foo : 'bar'};
}
},
getShopData: function () {
return myData;
}
};
}]);
(function(){
var appController = angular.module('ListerAppController', []);
appController.controller('ListerCtrl', ['$scope', '$rootScope', '$http', '$filter', '$timeout', '$sharedFactories', '$sharedServices',
function($scope, $rootScope, $http, $filter, $timeout, $sharedFactories, $sharedServices) {
$scope.items = $sharedServices.getShopData();
console.log($scope.items); // return myData -> null
}
})();
I've done this a bunch of times here's what I usually do in my resolve object for the routeProvider, need to make sure you return all promises appropriately in order for the route change to wait on resolve properties.
$routeProvider
.when('/path',
{
templateUrl: 'some/path/to/template.html',
controller: 'myCtrl',
resolve : {
'myData': ['mySrvc',function(mySrvc){
return mySrvc.someMethod().then(function(response){
return response.data;
},function(){
return {};
});
}]
}
}
);
Then the service:
angular.module('myApp.services').factory('mySrvc',['$http',function($http){
var _url = 'https://someurl.com/path/to/api';
return {
someMethod : function(vars){
if(angular.isDefined(vars)){
return $http.post(_url,$.param(vars),{headers:{'Content-Type':'application/x-www.form-urlencoded'}});
}else{
return $http.get(_url);
}
}
};
}]);
Then in the controller you need to inject the resolve parameters at the end of the parameter list for the controller.
angular.module('myApp.controllers').controller('myCtrl',['$scope','myData',function($scope,myData){
});
In your code, in the resolve object of the routeProvider you have a return from a function that returns nothing, try returning the promise from the $http and then the data.data_set value in the success function of your service.
I have found something like $q.defer, resolve and promise.
It holds up everything until the status "promise" is reached.
Here's a link
angular.module('sharedServiceApp', []).service('$sharedServices', ['$http', '$rootScope', '$q', function($http, $rootScope, $q) {
var myData = null;
return {
promise : function () {
if (!myData) {
var deferred = $q.defer();
$http({method : 'GET', url : '/shop/api/json', params : {
end : $rootScope.endmarkerSyncDataset,
page : 1,
per_page : $rootScope.itemsPerPage
}
}).success(function (data) {
myData = data.data_set;
deferred.resolve(data.data_set);
}).error(function(data, status, headers, config) {
deferred.reject("Error: request returned status " + status);
});
return deferred.promise;
} else {
return myData;
}
},
getShopData: function () {
return myData;
},
setShopData: function (data) {
myData= data;
}
};
}]);
In my angular module I wrote a generic http handler for all my ajax requests.'
I was expecting that I could use the service across controllers, but my problem is the promise seems to be global.
Once ControllerOne uses the mapi_loader service, when I load AnotherController (by ng-click="go('/$route_to_load_another_controller')"), AnotherController is loaded a promise that has already returned from ControllerOne even though the URL they fetch are totally different.
So I guess my question is how do I write a service I could use across controllers? Do I really need to write a separate service for each controller where their only difference in code is the URL passed for $http.jsonp?
angular.module('myAppControllers',[])
.service('mapi_loader', ['$http', function($http) {
var promise;
var myService = {
fetch: function(url) {
if ( !promise ) {
promise = $http.jsonp(url)
.then(function (response) {
return response.data.nodes;
});
}
return promise;
}
};
return myService;
}])
.controller('ControllerOne', ['$scope', 'mapi_loader', function ($scope, mapi_loader) {
mapi_loader
.fetch("http://host.com/mapi_data_for_controller_one?callback=JSON_CALLBACK")
.then(function(data) {
$scope.useme = data;
});
}])
.controller('AnotherController', ['$scope', 'mapi_loader', function ($scope, mapi_loader) {
mapi_loader
.fetch("http://host.com/mapi_data_for_another_controller?callback=JSON_CALLBACK")
.then(function(data) {
$scope.useme = data;
});
}])
;
try something like this
angular.module('myAppControllers',[])
.service('mapi_loader', function($http) {
var alreadyLoading = {};
return {
fetch: function(url) {
if ( url in alreadyLoading ) {
return alreadyLoading[url];
}
return alreadyLoading[url] = $http.jsonp(url)
.then(function (response) {
delete alreadyLoading[url];
return response.data.nodes;
});
}
};
})
.controller('ControllerOne', function ($scope, mapi_loader) {
...
})
.controller('AnotherController', function ($scope, mapi_loader) {
...
});