I'm not quite sure what I'm doing wrong, but it seems that my profile doesn't resolve by the time we get to the MainCtrl. The user however does, resolve. Am I, perhaps not fetching the profile information properly in the Auth Service?
Router:
angular.module('app')
.config(function ($stateProvide) {
$stateProvider
.state('main', {
url: '/main',
templateUrl: 'app/main/main',
controller: 'MainCtrl',
resolve: {
user: function (Auth) {
return Auth.getUser();
},
profile: function (user) {
return Auth.getProfile();
}
}
});
});
Controller:
angular.module('app')
.controller('MainCtrl', function ($scope, user, profile) {
$scope.user = user;
$scope.profile = profile; <- DOESNT RESOLVE
});
Auth Service:
angular.module('app')
.factory('Auth', function ($firebaseSimpleLogin, $firebase, FBURL) {
var ref = new Firebase(FBURL);
var auth = $firebaseSimpleLogin(ref);
var Auth = {
user: {},
getUser: function () {
return auth.$getCurrentUser();
},
getProfile: function(uid) {
return $firebase(ref.child('users').child(uid)).$asObject();
}
};
return Auth;
});
Something like
auth.$getCurrentUser()
returns a promise so you need a
.then(function(user) {
event before your callback complete
In your case you may just resolve on the then, something like
Auth.getUser().then(function(user){ return user; });
Also $asObject() needs $loaded() for it's promise
var obj = $firebase(ref).$asObject();
obj.$loaded()
.then(function(data) {})
Try this structure for your promises:
var fetchSomething = function (action, params) {
var promise = $http({
method: 'POST',
url: 'someurl to the firebase',
data: params,
headers: {
'Access-Control-Allow-Origin': true,
'Content-Type': 'application/json'
}
}).success(function (data, status, headers, config) {
return data;
});
return promise;
};
Related
I have 2 modules that should be connected.
The main module, called mainPage has the second module, called router, injected. They are in separate files. I want to use my service called userPropagatorService in mainPage and in router.
This service should be used to get and set currently logged in user.
I tried to inject service to router module, but I get errors.
How can I achieve this?
mainPage file:
var app = angular.module('mainPage',['reg','router']);
//Returns a promise which generates our user.
app.factory('userLoginService',['$http',function ($http){
return{
loginService: function(username,password){
var info = {username:username, password:password}
var user={};
//Returning http request because of promises
return $http({
url: 'webapi/users/login',
method: 'POST',
data: info,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data:{username: info.username, password: info.password}
}).then(function (response)
{
user = response.data
return user;
});
}
}
}]);
app.service('userPropagatorService', function(){
return{
get:function(){
return this.u;
},
set:function(user){
this.u = user;
}
}
});
router file:
var r = angular.module('router',['ngRoute'])
.config(['$routeProvider', '$locationProvider','userPropagatorService',
function($routeProvider, $locationProvider, userPropagatorService) {
$locationProvider.html5Mode(true);
$routeProvider
.when("/home",{
templateUrl: "pages/MainPage.html",
controller:"homeController"
})
.when("/forums",{
templateUrl: "pages/forumsPage.html",
controller:"forumController"
})
.when("/topics",{
templateUrl: "pages/topicsPage.html",
controller:"topicsController"
})
.when("/comments",{
templateUrl: "pages/commentsPage.html",
controller:"commentsController"
})
.otherwise({
redirectTo:"/home"
});
}])
.controller("homeController",['$scope','$http',function($scope,$http){
/*$http({
url: "webapi/forums/all",
method:"GET"
})
.then(function(response){
console.log("YEA!");
console.log(response.data);
},
function(response){
console.log("NO:(");
})*/
$scope.username = "visitor!"
$scope.user = userPropagatorService.get();
if($scope.user != null){
$scope.username=$scope.user.username + "!";
}
}])
.controller("forumController",['$scope','$http',function($scope,$http){
$scope.username = "visitor!"
}])
.controller("commentsController",['$scope','$http',function($scope,$http){
$scope.username = "visitor!"
}]);
If you want to use the userLoginService in the router module, it needs to be broken out of the main app.
var app = angular.module('mainPage',['reg','router']);
angular.module("services",[])
.factory('userLoginService',['$http',function ($http){
return{
//Service code here
};
}]);
Then add it as a dependency in the router module:
var r = angular.module('router',['ngRoute','services'])
You cant inject Service "userPropagatorService" in config block.
Make it a provider with $method and return function from there .
ang.provider('userPropagatorService', function(){
return{
get:function(){
console.log("in get");
},
set:function(user){
},
$get: function(){
return {
meth1: function(){
}
}
}
}
});
ang.config(function(userPropagatorServiceProvider){
console.log(userPropagatorServiceProvider.meth1())
})
Component:
crudModule.js
var crudModule = angular.module('crudModule', ['ui.router', 'smart-table', 'ngCookies', 'ui.bootstrap', 'angularModalService', 'dialogs', 'remoteValidation']);
angular.module('crudModule').component('applicationInfo', {
templateUrl: 'infoApplication.html',
controller: 'applicationInfoCtrl'
});
applicationInfoCtrl.js:
var crudModule = angular.module('crudModule')
crudModule.controller('applicationInfoCtrl', ['httpService', '$scope', function($http, $scope, $cookies, $stateParams, httpService) {
httpService.httpGetRequest("http://localhost:8080/applications/" + $stateParams.id).then(function success(response) {
$scope.application = response.data;
});
$scope.getApiKey = function () {
httpService.httpGetRequest('http://localhost:8080/applications/generateApiKey').then(function success(response) {
$scope.application.apikey = response.data.apikey;
$scope.application.apisecret = response.data.apisecret
})
};
$scope.send = function (object, url) {
httpService.httpPostRequest(object, url + "/" + $stateParams.id).catch(function(error) {
console.log('There has been a problem with your fetch operation: ' + error.message);
}).then(function success(response){
});
}
}]);
httpService.js:
var crudModule = angular.module('crudModule')
crudModule.factory('httpService', function($http) {
return {
httpGetRequest: function (url) {
return $http({
method: 'GET',
url: url
})
},
httpPostRequest: function (object, url){
return $http({
method:'POST',
url: url,
data: object
})
}
}
});
I am getting error:
Cannot read property 'httpGetRequest' of undefined.
I have injected my httpService and i dont find any mistakes yet
The problem is the order of parameters in your controller, it should be
crudModule.controller('applicationInfoCtrl', ['$http','httpService', '$scope','$cookies','$stateParams' function(http,httpService, $scope,$cookies,$stateParams) {
}
/TypeError: Cannot read property 'getToken' of undefined/
I am trying to call getToken function which is defined in the factory function.
Both directive and factories are in separate .js file
but it is throwing an error and is not able to access the function.
angular.module('pesaveWeb')
.directive('goals', function goalsDrctv ($timeout) {
'use strict';
return {
restrict: 'E',
replace: true,
scope: true,
templateUrl: "js/directives/goals.tmpl.html",
controllerAs: 'savings',
controller: function ($routeParams, $scope,
savingsFactory,tokenFactory) {
this.message = {};
var token=tokenFactory.getToken();
var getGoals = savingsFactory.getGoals(token);
if (getGoals) {
getGoals.then( angular.bind(this, function (response) {
savingsFactory.message = response;
this.message = savingsFactory.message;
alert(JSON.stringify(this.message));
}) );
}
}
}
});
angular.module('pesaveWeb').factory('tokenFactory', function tokenFactory ($http,$routeParams) {
'use strict';
var obj = {};
obj.getToken = function () {
return $http({
method: 'POST',
url: "../api/v1/getToken",
headers : {
'Content-Type':'application/json',
'X-API-KEY':'04g4g00c04ks4sokgkoosg0kwww0cww4www0kc80',
'Authorization':"Basic cGVzYXZlQXBwOkNDNTVzV0FwUW0zYWxpazlLNTcwTTFXQ1RNOUJ1TmZS"
},
data: {"grant_type":"client_credentials"}
}) .success(function (data) {
})
.error(function (data) {
});
};
});
Your factory function needs to return the obj you are using to bind the function to.
angular.module('pesaveWeb').factory('tokenFactory', function tokenFactory ($http,$routeParams) {
'use strict';
var obj = {};
obj.getToken = function () {
return $http({
method: 'POST',
url: "../api/v1/getToken",
headers : {
'Content-Type':'application/json',
'X-API-KEY':'04g4g00c04ks4sokgkoosg0kwww0cww4www0kc80',
'Authorization':"Basic cGVzYXZlQXBwOkNDNTVzV0FwUW0zYWxpazlLNTcwTTFXQ1RNOUJ1TmZS"
},
data: {"grant_type":"client_credentials"}
}) .success(function (data) {
})
.error(function (data) {
});
};
return obj;
});
Also, another potential problem is the getToken() function might not work as expected. You should use a "promise" for resolving the value of token in your getToken() function using Angular's $q service. Check out its documentation here
$http.post('http://localhost:7001/v1/sessions', {
data: {
username: $scope.user.username,
password: $scope.user.password,
type: 'sessions'
}
})
.then(function(response) {
if(response.data.data.token) {
$http.defaults.headers.common.Authorization = response.data.data.token;
$state.go('app.dashboard');
} else {
$scope.authError = response;
}
}, function(x) {
$scope.authError = 'Server Error';
});
I can confirm that the if condition gets called and a response.data.data.token is present.
It goes to the app.dashboard state but is intercepted by my ui-router:
$stateProvider.state('app', {
abstract: true,
url: '/app',
templateUrl: 'tpl/app.html',
resolve: {
current_user: ['$http', function($http) {
return $http.get('http://localhost:7001/v1/users/4/entities');
}]
}
})
That call, however, does not have anything set in the header. I thought that $http.defaults would set a default value in the header. What am I doing incorrectly?
You must set the default headers in the config method and not in your service.
Example:
myApp.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common['Content-Type'] = 'application/json; charset=utf-8';
}]);
Only in config you can configure the httpProvider. If you try to do that inside your service, it won't affect the $httpProvider service at all.
EDIT:
You must make use Interceptors in this scenario.
For purposes of global error handling, authentication, or any kind of
synchronous or asynchronous pre-processing of request or
postprocessing of responses, it is desirable to be able to intercept
requests before they are handed to the server and responses before
they are handed over to the application code that initiated these
requests.
Refer Angular Docs Interceptor section
Just some sample code:
app.service('APIInterceptor', function($rootScope, UserService) {
var service = this;
service.request = function(config) {
// check if the token is available. Once the token is available get it here from the UserService.
var access_token = UserService.getToken() || "unauthorized";
if (access_token) {
config.headers.authorization = access_token;
}
return config;
};
service.responseError = function(response) {
return response;
};
})
In your config
$httpProvider.interceptors.push('APIInterceptor');
I would prefered you to one service to use sharable data.
Code
app.service(dataService, function(){
this.data = {}
this.getData = function(){
return data;
};
this.setTokenData = function(token){
data.token = token;
}
});
Now your code would be while setting token you could use dataService
if(response.data.data.token) {
dataService.setTokenData(response.data.data.token);
$http.defaults.headers.common.Authorization = dataService.data.token; //dataService.getData().token;
$state.go('app.dashboard');
} else {
$scope.authError = response;
}
Then from service resolve you could use
$stateProvider.state('app', {
abstract: true,
url: '/app',
templateUrl: 'tpl/app.html',
resolve: {
current_user: ['$http', 'dataService', function($http, dataService) {
$http.defaults.headers.common.Authorization = dataService.getData().token;
return $http.get('http://localhost:7001/v1/users/4/entities');
}]
}
})
Consider the code:
var myApp = angular.module('myApp', []);
The routes:
myApp.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'app.html',
controller:myAppController,
resolve:{
resolveData:function(Resolver){
return Resolver();
}
}
});
});
Resolve:
myApp.factory('Resolver', ['$http', function($http){
return function(){
return $http({url: '/someurl',method: "GET"}).then(function(data) {
// dependent call 1
$http({url: '/someotherurl',method: "GET" }).then(function(data) {
});
// dependent call 2
$http({url: '/someanotherurl',method: "GET" }).then(function(data) {
});
});
}
}]);
Above I have nested 2 calls inside one as they are dependent on the data returned by the parent call.
What I want to do: return the Resolver when all of them have completed and not just the parent call.
I cannot use $q.all() because 2 of the calls are dependent of the first call.
In short, myAppController must be loaded only after all the 3 calls have completed.
You should be using chaining promise and $q service to solve your problem .Just use the below sample code it should work
myApp.factory('Resolver', ['$http','$q', function ($http,$q) {
return function () {
var deferred = $q.defer();
$http({ url: '/someurl', method: "GET" }).then(function (data) {
return $http({ url: '/someurl', method: "GET" })
}).then(function (data) {
return $http({ url: '/someanotherurl', method: "GET" })
}).then(function (data) {
deferred.resolve(data);
});
return deferred.promise;
}
}]);
This works for me:
resolve : {
message: function($q, $route, Restangular) {
var msgId = $route.current.params.msgId;
var deferred = $q.defer();
Restangular.one('message', msgId).get().then(function(message) {
Restangular.one('file', message.audioFile.id).get().then(function (blob) {
message.blob = blob;
deferred.resolve(message);
});
});
return deferred.promise;
}
}