i am trying to combine a cordova application with angularjs and ionic framework with a rest service for user login and register.
this is the code of data.js which connects to the rest api
app.factory("Data", ['$http', 'toaster',
function ($http, toaster) { // This service connects to our REST API
var serviceBase = 'http://blace.co/task_manager/v1/';
var obj = {};
obj.toast = function (data) {
toaster.pop(data.status, "", data.message, 10000, 'trustedHtml');
}
obj.get = function (q) {
return $http.get(serviceBase + q).then(function (results) {
return results.data;
});
};
obj.post = function (q, object) {
console.log(object);
return $http.post(serviceBase + q, object).then(function (results) {
return results.data;
});
};
obj.put = function (q, object) {
return $http.put(serviceBase + q, object).then(function (results) {
return results.data;
});
};
obj.delete = function (q) {
return $http.delete(serviceBase + q).then(function (results) {
return results.data;
});
};
return obj;
}]);
and this is the code of my controller authCtrl.js
app.controller('authCtrl', function ($scope, $rootScope, $routeParams, $location, $http, Data) {
//initially set those objects to null to avoid undefined error
$scope.login = {};
$scope.register = {};
$scope.doLogin = function (login) {
Data.post('login').then(function (results) {
Data.toast(results);
if (results.status == "success") {
$location.path('dashboard');
}
});
};
$scope.register = {};
$scope.Register = function (register) {
Data.post('register').then(function (results) {
Data.toast(results);
if (results.status == "success") {
$location.path('dashboard');
}
});
};
$scope.logout = function () {
Data.get('logout').then(function (results) {
Data.toast(results);
$location.path('login');
});
}
});
this one is the part of my rest api for the registar part
$app->post('/register', function() use ($app) {
// check for required params
verifyRequiredParams(array('name', 'email', 'password'));
$response = array();
// reading post params
$name = $app->request->post('name');
$email = $app->request->post('email');
$password = $app->request->post('password');
// validating email address
validateEmail($email);
$db = new DbHandler();
$res = $db->createUser($name, $email, $password);
if ($res == USER_CREATED_SUCCESSFULLY) {
$response["error"] = false;
$response["message"] = "You are successfully registered";
} else if ($res == USER_CREATE_FAILED) {
$response["error"] = true;
$response["message"] = "Oops! An error occurred while registereing";
} else if ($res == USER_ALREADY_EXISTED) {
$response["error"] = true;
$response["message"] = "Sorry, this email already existed";
}
// echo json response
echoRespnse(201, $response);
});
the rest api is working perfectly and i have checked it with Advanced Rest Client
you can see it here
image
in internet explorer i have this error
BAD REQUEST - The request could not be processed by the server due to invalid syntax. (XHR): POST
i think the problem is that
By default, the $http service will transform the outgoing request by serializing the data as JSON and then posting it with the content- type, "application/json". When we want to post the value as a FORM post, we need to change the serialization algorithm and post the data with the content-type, "application/x-www-form-urlencoded".
another post
but i do not know how to implement this
any idea is appreciated!
thank you
Related
What is wrong with the code it's not working, I am trying to request call web service from backend written in spring, the value passing from backend is token wrapped, I am trying to run the code on client side but form is not passing any value.
auth.js
'use strict';
angular. module('app')
.factory('Auth', [ '$http', '$rootScope', '$window', 'Session', 'AUTH_EVENTS',
function($http, $rootScope, $window, Session, AUTH_EVENTS) {
var authService = {};
this.isLoggedIn = function isLoggedIn(){
return session.getUser() !== null;
};
//the login function
authService.login = function(user, success, error) {
$http.post('URL: http://xxx.xxx.x.xx:xxxx/xxxx/authenticateUser').success(function(authData) {
//user is returned with his data from the db
var users = data.users;
if(users[user.username]){
var loginData = users[user.username];
//insert your custom login function here
if(user.username == loginData.username && user.password == loginData.username){
localStorageService.set(['userInfo'],
{ token: result.access_token, userName: loginData.userName });
//delete password no/t to be seen clientside
delete loginData.password;
//update current user into the Session service or $rootScope.currentUser
//whatever you prefer
Session.create(loginData);
//or
$rootScope.currentUser = loginData;
//fire event of successful login
$rootScope.$broadcast(AUTH_EVENTS.loginSuccess);
//run success function
success(loginData);
} else{
//OR ELSE
//unsuccessful login, fire login failed event for
//the according functions to run
$rootScope.$broadcast(AUTH_EVENTS.loginFailed);
error();
}
}
});
};
//check if the user is authenticated
authService.isAuthenticated = function() {
return !!Session.user;
};
//check if the user is authorized to access the next route
//this function can be also used on element level
//e.g. <p ng-if="isAuthorized(authorizedRoles)">show this only to admins</p>
authService.isAuthorized = function(authorizedRoles) {
if (!angular.isArray(authorizedRoles)) {
authorizedRoles = [authorizedRoles];
}
return (authService.isAuthenticated() &&
authorizedRoles.indexOf(Session.userRole) !== -1);
};
//log out the user and broadcast the logoutSuccess event
authService.logout = function(){
Session.destroy();
localStorageService.removeItem("userInfo");
$rootScope.$broadcast(AUTH_EVENTS.logoutSuccess);
}
return authService;
} ]);
authInterceptor
(function () {
'use strict';
var app = angular.module('app');
var factoryId = 'authInterceptor';
app.factory(factoryId, authInterceptor);
authInterceptor.$inject = ['$q', '$location', 'localStorageService', $rootScope, $http];
function authInterceptor($q, $location, localStorageService) {
var service = {
request: request,
responseError: responseError,
};
return service;
function request(config) {
config.headers = config.headers || {};
var authData = localStorageService.get('authorizationData');
if (authData) {
config.headers.Authorization = 'Bearer ' + authData.token;
}
return config;
}
function responseError(error) {
var loggedIn = false;
var authData = localStorageService.get('authorizationData');
if (authData) {
loggedIn = true;
}
//We only want to go to the login page if the user is not
//logged in. If the user is logged in and they get a 401 is
//because they don't have access to the resource requested.
if (error.status === 401 && !loggedIn) {
$location.path('/login').replace();
}
return $q.reject(error);
}
}
})();
I try to make facebook registration module in my app. Facebook API is faster than my Angular controller, so promise should be used here. The problem is that $q seems to be an empty object and defer function is undefined.
module:
var module = angular.module('app.facebook', []);
module.constant("fbAppId", 'herecomesmycode');
module.factory('facebook', FacebookAPI);
FacebookAPI.$inject = ['$ionicLoading', '$q', '$ionicPlatform', '$state', 'authService', 'datacontext', '$location'];
function FacebookAPI(UserService, $q, $ionicLoading, fbAppId, $state, authService, datacontext, $location) {
return {
fbLoginSuccess: fbLoginSuccess,
fbLoginError: fbLoginError,
getFacebookProfileInfo: getFacebookProfileInfo,
fbLogin: fbLogin,
fbRegister: fbRegister
};
and here $q.defer is undefined:
function fbRegister() {
console.log($q.defer);
if (!cordova) {
facebookConnectPlugin.browserInit(fbAppId);
}
var data;
facebookConnectPlugin.getLoginStatus(function (response) {
if (response.status !== 'connected') {
facebookConnectPlugin.login(["email"],
function(response) {
data = getApiData();
},
function(response) {
});
} else {
data = getApiData();
}
});
}
Without using promise, it gets fast from API but all variables I want to fill with values from API, are initiated before API finishes and are undefined.
The whole module:
(function() {
'use strict';
var module = angular.module('app.facebook', []);
module.constant("fbAppId", 'myappkey');
module.factory('facebook', FacebookAPI);
FacebookAPI.$inject = ['$ionicLoading', '$ionicPlatform', '$state', 'authService', '$q'];
function FacebookAPI(UserService, $ionicLoading, fbAppId, $state, authService, $q) {
return {
fbLoginSuccess: fbLoginSuccess,
fbLoginError: fbLoginError,
getFacebookProfileInfo: getFacebookProfileInfo,
fbLogin: fbLogin,
fbRegister: fbRegister
}
function fbRegister() {
console.log($q);
if (!cordova) {
facebookConnectPlugin.browserInit(fbAppId);
}
var data;
facebookConnectPlugin.getLoginStatus(function (response) {
if (response.status !== 'connected') {
facebookConnectPlugin.login(["email"],
function(response) {
data = getApiData();
},
function(response) {
});
} else {
data = getApiData();
}
});
}
function getApiData() {
var formData = {};
facebookConnectPlugin.api("me/?fields=id,first_name,last_name,link,gender,email,birthday", ["public_profile", "email", "user_birthday"],
function (result) {
if (result.gender == "male") {
result.gender = '1';
} else {
result.gender = '2';
}
formData = {
name: result.first_name + " " + result.last_name,
email: result.email,
birthday: new Date(result.birthday),
gender: result.gender
}
console.log("moduĊ" + formData);//here we have nice and neat data
return formData;
}, function(res) {
});
}
};
//This is the success callback from the login method
function fbLoginSuccess(response) {
var fbLogged = $q.defer();
if (!response.authResponse) {
fbLoginError("Cannot find the authResponse");
return;
}
var expDate = new Date(
new Date().getTime() + response.authResponse.expiresIn * 1000
).toISOString();
var authData = {
id: String(response.authResponse.userID),
access_token: response.authResponse.accessToken,
expiration_date: expDate
}
authService.facebookLogin(response.authResponse.accessToken).then(function() {
fbLogged.resolve(authData);
});
};
//This is the fail callback from the login method
function fbLoginError(error) {
var fbLogged = $q.defer();
fbLogged.reject(error);
alert(error);
$ionicLoading.hide();
};
//this method is to get the user profile info from the facebook api
function getFacebookProfileInfo() {
var info = $q.defer();
facebookConnectPlugin.api('/me', "",
function(response) {
info.resolve(response);
},
function(response) {
info.reject(response);
}
);
return info.promise;
}
//This method is executed when the user press the "Login with facebook" button
function fbLogin() {
if (!cordova) {
//this is for browser only
facebookConnectPlugin.browserInit(fbAppId);
}
//check if we have user's data stored
var user = UserService.getUser();
facebookConnectPlugin.getLoginStatus(function(success) {
//alert(JSON.stringify(success, null, 3));
if (success.status === 'connected') {
// the user is logged in and has authenticated your app, and response.authResponse supplies
// the user's ID, a valid access token, a signed request, and the time the access token
// and signed request each expire
facebookConnectPlugin.api("me/?fields=id,first_name,last_name,link,gender,email", ["public_profile", "email"],
function(result) {
//alert("Result: " + JSON.stringify(result));
//alert(result.first_name);
})
var accessToken = success.authResponse.accessToken;
authService.facebookLogin(accessToken).then(function() {
$state.go('app.map');
}, function(err) { alert('auth failed: ' + JSON.stringify(err, null, 2)); });
} else {
//if (success.status === 'not_authorized') the user is logged in to Facebook, but has not authenticated your app
//else The person is not logged into Facebook, so we're not sure if they are logged into this app or not.
$ionicLoading.show({
template: 'Loging in...'
});
// permissions from facebook
facebookConnectPlugin.login([
'email',
'public_profile',
'user_about_me',
'user_likes',
'user_location',
'read_stream',
'user_photos'
], fbLoginSuccess, fbLoginError);
fbLogged.promise.then(function(authData) {
var fb_uid = authData.id,
fb_access_token = authData.access_token;
//get user info from FB
getFacebookProfileInfo().then(function(data) {
var user = data;
user.picture = "http://graph.facebook.com/" + fb_uid + "/picture?type=large";
user.access_token = fb_access_token;
//save the user data
//store it on local storage but it should be save it on a database
UserService.setUser(user);
$ionicLoading.hide();
$state.go('app.map');
});
});
}
});
}
})();
I'm learning angular, and I'm trying to use a service to store data from an HTTP request, and be able to access it later.
Problem:
Data object is empty every time I try to retrieve it, which causes it to make a new call. I'm using this in the context of a ui-router resolve(does this cause the service to re-instantiate and lose the data)?
Service:
evaApp.factory('userService', ['$http', '$q', function ($http, $q) {
var user = {};
return {
makeRequest : function(url, uid) {
var deferred = $q.defer();
if (!uid) { uid = ''; };
$http.get(url, { params : { userId : uid } }).then(function (res) {
deferred.resolve(res.data);
});
return deferred.promise;
},
getUser : function(userId) {
console.log(user); // user is always empty
if(!user || !user._id) {
user = this.makeRequest('/api/user/get', userId);
};
return user;
}
}
}]);
Addition:
Data storage is working using PSL's solution. Data retrieval is not: Link to question.
this.makeRequest returns a promise and it does not have a _.id property which is causing it to make the ajax call again (due the condition if(!user || !user._id) {). just return the promise itself from getUser and use it. Remember you are not assigning the user instead assigning a promise by doing user = this.makeRequest('/api/user/get', userId);
Instead just do:-
var user = {};
getUser : function(userId) {
return user[userId] || (user[userId] = this.makeRequest('/api/user/get', userId)
.catch(function(){ user = null })); //nullify in case of error for retry
}
and in make request just do:
makeRequest : function(url, uid) {
if (!uid) { uid = ''; };
return $http.get(url, { params : { userId : uid } }).then(function (res) {
return res.data;
});
},
and while making call from controller you would do:-
mySvc.getUser(userId).then(function(user){
myCtrlInstance.user = user;
});
Note: Avoid using deferred anti-pattern when you already have an operation that returns a promise.
You can make something like this:
evaApp.factory('userService', ['$http', '$q', function ($http, $q) {
var user = {};
return {
makeRequest : function(url, uid) {
var deferred = $q.defer();
if (!uid) { uid = ''; };
$http.get(url, { params : { userId : uid } }).then(function (res) {
user = res.data;
deferred.resolve(user);
});
return deferred.promise;
},
getUser : function(userId) {
console.log(user); // user is always empty
if(!user || !user._id) {
return this.makeRequest('/api/user/get', userId);
};
var deferred = $q.defer();
deferred.resolve(user);
return deferred.promise;
}
}
}]);
And then get the user details like this (the 1 is just for the example):
userService.getUser(1).then(
function( data ) {
console.log(data);
}
);
I'm trying to move this http request to a service and because I'm new to AngularJS I'm having some real issues. Can you help me figure out how to move not only the http request but the viewValue over from the controller to the service?
app.controller('poController',
function poController($scope, $http, poService) {
$scope.test = '';
$scope.fetchPartNumbers = function ($viewValue) {
return $http.get('/api/GetInventoryById/' + $viewValue
).then(function (res) {
var PartNumbers = [];
angular.forEach(res.data, function (item) {
PartNumbers.push(item.PartNumber);
});
return PartNumbers;
});
};
});
I can move the http request over, but I'm not sure how to push the $viewValue over or have it accessible in the service as well.
app.factory('poService', function () {
});
Just add it as a parameter:
app.factory('poService', function ($http) {
return {
fetchPartNumbers: function(value) {
return $http.get('/api/GetInventoryById/' + value).then(function(res) {
var PartNumbers = [];
angular.forEach(res.data, function (item) {
PartNumbers.push(item.PartNumber);
});
return PartNumbers;
});
}
}
});
And the controller
$scope.fetchPartNumbers = function ($viewValue) {
poService.fetchPartNumbers($viewValue).then(function(data) {
console.log(data)
});
}
i am trying to write a Factory for my WebApiCall
so ive written this :
mod.factory('AccountService', function($http) {
var service = {};
var onError = function(response) {
if (response == '') {
return ['Timeout Occured !'];
}
var errors = [];
for (var key in response.ModelState) {
for (var i = 0; i < response.ModelState[key].length; i++) {
errors.push(response.ModelState[key][i]);
}
}
return errors;
};
var onSuccess = function(response) {
return true;
}
service.Login = function(credentials) {
$http.put('http://localhost:9239/Api/Account/', credentials).success(function(data) {
return onSuccess(response);
}).error(function (response) {
return onError(response);
});
};
return service;
});
The Controller :
mod.controller('accountCtrl', function ($scope, $http, $window, $location, ConfigService, AccountService) {
$scope.credentials = { username: '', password: '' };
$scope.Errors = [];
$scope.registerModel = { username: '', password: '', passwordrepeat: '', email: '', emailrepeat: '' };
$scope.isLoading = false;
$scope.Login = function () {
$scope.Errors = [];
$scope.isLoading = true;
AccountService.Login($scope.credentials).onSuccess(function(response) {
$window.sessionStorage.setItem('loginToken', data.SuccessMessages[0]);
if (data.SuccessMessages[1] != '') {
$window.sessionStorage.setItem('groupId', data.SuccessMessages[1]);
}
$scope.isLoading = false;
$location.path('/Home');
}).onError(function(errors) {
$scope.Errors.push(errors);
$scope.isLoading = false;
});
Ok when i Login the Login MEthod is called. But wenn the Success or Error Method from $http is called it doesnt return my onSuccess or onError function.
I think i made some mistakes did i ?
A few things, $http promises don't have onSuccess or onError callbacks, they're sucess and error instead. In your service you are not returning the $http promise, and then you call sucess and error on it, of course it won't work! $http calls, much like Ajax calls anywhere take place asynchronously, meaning that you cant simply return a value in the success/error callback, you can however return a promise:
service.Login = function(credentials) {
return $http.put('http://localhost:9239/Api/Account/', credentials)
};
and in your controller you could use that like:
AccountService.Login($scope.credentials).then(function(data) {//success callback
$window.sessionStorage.setItem('loginToken', data.SuccessMessages[0]);
if (data.SuccessMessages[1] != '') {
$window.sessionStorage.setItem('groupId', data.SuccessMessages[1]);
}
$scope.isLoading = false;
$location.path('/Home');
},function(errors) {//error callback
$scope.Errors.push(errors);
$scope.isLoading = false;
})
when you call then on the promise, it gets executed when the promise is resolved, the first function is success callback and the second is the error callback.