How to launch a method on all ng-click events AngularJS - javascript

I have made a web application in Node.js that lets users manage their mongoDB database. I have several click events that do CRUD actions that change the status of the database. On each ng-click I call the corresponding function to do the CRUD action. The problem is that, in each of these functions I call the a method called refresh which updates the page so it matches the current database info. Is there a way, I can just hook up the refresh function to be called whenever a ng-click event has ended?
Examples
$scope.dropDB = function (DB) {
$http.post('/dropDB', JSON.stringify({ 'DB': DB })).success(function (response) {
refresh();
});
};
$scope.addDB = function (DB) {
try{
var objson = JSON.stringify({ 'DB': DB }) ;
$http.post('/addDB', objson).success(function (response) {
console.log("DB Added: ");
refresh();
});
}catch(ex){
alert("Not a valid input type");
}
};

Make wrapper factory for your http call
['$http', function($http) {
return function(method, route, body) {
var args = method === 'POST' ? [route, body] : [route];
return new Promise(function(resolve, reject) {
return $http[method].apply(this, args).then(function(res) {
refresh();
resolve(res)
}).catch(function(err) {
reject(err);
})
});
}
}];
Then you can use it in your controller
myFactory('POST', '/database', {foo: 'bar'}).then(function(res) {
// at this point refresh() was already called
})

Related

Using a value from a get with ngResource in the controller

I'm struggling with using the value that I got from a 'get' in my controller.
This is my code in my controller
vm.user;
function onInit(){
loadUser(vm.queryParams.id[0]);
console.log(vm.user);
}
function loadUser(UserId) {
var defer = $q.defer();
User.get({ id: userId }).$promise.then(function (user) {
vm.user = user;
defer.resolve();
});
return defer.promise;
};
When I print the vm.user in the onInit() it is undefined. While when I look on the view where vm.user is called it just shows me the correct values of the user. So it's not known after the loadUser() in the controller but it is in my view.
I would like to first 'get' the user and then use it for further logic in the onInit(). How to retrieve the user properly so I can further use it and call its values in the onInit()?
You have to wait till the execution of loadUser() is finished so as the get the value of user.You can use the promise returned like this and do any calcualtions on it.
vm.user;
function onInit(){
var promise=loadUser(vm.queryParams.id[0]);
promise.then(function(response){
console.log(response);
});
}
function loadUser(UserId) {
var defer = $q.defer();
User.get({ id: userId }).$promise.then(function (user) {
vm.user = user;
defer.resolve(vm.user);
});
return defer.promise;
};
Immediately invoke your init function at the beginning of your controller and convert your loadUser function to a service since its a get action. Your service will return the user which you can then set.
(Declare at top of controller):
init();
function init(){
loadUserService.loadUser(UserId)
.then(function (user) {
vm.user = user;
defer.resolve();
})
}

Why doesn't my Google authentication work in Firebase?

I've modeled my Google logon after the example provided by Firebase at http://jsfiddle.net/firebase/a221m6pb/
However when I run my code (https://firetest-wadeziegler.c9.io/logon) the popup goes blank after selecting user and never closes. The callback code is never executed. Any ideas why this isn't working?
Authorized Domains for OAuth Redirects:
firetest-wadeziegler.c9.io
logon.js
function logonWithGoogle() {
var promise = session.logonWithGoogle();
$.when(promise)
.then(function (authData) {
setTimeout(function() { window.location.replace('/') }, 0);
}, function (error) {
showMessageBox('Logon Failed', error);
});
}
session.js
var session = new Session();
function Session() {
this.firebase = new Firebase("https://glowing-inferno-3026.firebaseio.com");
this.firebase.onAuth(function globalOnAuth(authData) { } );
}
Session.prototype.isLoggedOn = function() {
return this.firebase.getAuth() != null;
}
// Returns Promise object
Session.prototype.logonWithGoogle = function() {
var deferred = $.Deferred();
this.firebase.authWithOAuthPopup("google",
function (err, user) {
if (err) {
deferred.reject(err);
}
if (user) {
deferred.resolve(user);
}
}
, {
remember: "sessionOnly",
scope: "email,profile"
});
return deferred.promise();
}
The problem was with the calling code and the lack of a preventDefault() on the click within a form. The page reloaded right after the click but it was so quick I didn't notice. Stupid mistake.
<button onClick="logonWithGoogle(); return false /* prevent submit */">

AngularJS - return promise success value to the calling function

I am learning AngularJS and AJAX.I am trying to assign the data being returned by the success function to user. grantRole belongs to Auth service. The value of user as I currently have it is a promise. How do I assign the returned data on success to user?
$scope.grantRole = function(user) {
user = Auth.grantRole(user).then(
function success(data){
return data;
},
function error(err){
console.log(err);
}
);
grantRole: function(user,callback) {
var cb = callback || angular.noop;
var data = {id: user._id,controller:'role'};
return User.update({id: user._id,controller:'role'},data,
function(user) {
return cb(user);
}, function(err) {
return cb(err);
}).$promise;
};
The current value of user being a promise is correct. Once the promise gets resolved, it will be assigned to the data returned on success.
But you have to be careful when reassigning objects or arrays. See Service variable not updating in controller
E.g., don't do this: user = ...;
Rather, do this: angular.copy(newInfo, user) or this: user.email = ...
$scope.grantRole = function(user) {
Auth.grantRole(user).then(
function success(data){
angular.copy(data, user);
},
function error(err){
console.log(err);
}
);

Returned value from promise is not what is expected

I have some logic where I'm trying to build a "person" object and I have a method called getProvider where i'm basically fetching a provider from mongo and assiging it to person.provider.
Since the call to mongo is async, i'm trying to use promises. The value seems to be correct everywhere i've logged it except in my .then method. It shows {"source": {}} and I have no idea why.
Here's my output:
data =
MYPROVIDER
provider =
MYPROVIDER
after addProvider
{"source":{}}
...
configDone.promise.then(function () {
return addProvider();
}).then(function() {
console.log('after addProvider');
console.log(JSON.stringify(people[0].provider)); // SHOWS {"source": {}}. WHY IS IT DOING THIS?
callback(null, people);
}).fail(function (err) {
callback(err);
});
function addProvider() {
var promises = [];
people.forEach(function(person){
promises.push(person.provider = getProvider(person.id, db));
});
return Q.all(promises).spread(function(provider) {
console.log('provider = ');
console.log(provider); // SHOWS CORRECT PROVIDER HERE
});
}
// Gets a provider for a specific person id
var getProvider = function(id, db) {
var def = Q.defer();
db.collection('providerLists').findOne({id: id}, function (err, data) {
if (err) {
def.reject(err);
} else {
console.log('data = ');
console.log(data.ListName); // SHOWS CORRECT VALUE
def.resolve(data.ListName);
}
});
return def.promise;
}
people[0].provider should be pointing at a resolved promise. If you attach a then handler to it you will see the expected provider value:
people[0].provider.then(function(provider) {
console.log(JSON.stringify(provider);
});
If you wanted to have the provider to be a value on each person of the people array you could update your addProvider function as follows:
function addProvider() {
var promises = [];
people.forEach(function(person){
promises.push(getProvider(person.id, db)
.then(function(provider) {
person.provider = provider;
});
});
return Q.all(promises).spread(function(provider) {
console.log('provider = ');
console.log(provider); // SHOWS CORRECT PROVIDER HERE
});
}

Chaining multiple promises (handling callbacks)

I am having some difficulties with promises when it comes chaining multiple ones. The confusion is distinguishing how to properly take advantage of promises & their difference with Callbacks. I noticed that callbacks sometime fire regardless a promise is resolved or not, making the below implementation unreliable..(Unless my syntax & logic are wrong) I read the official documentation and came up with this, but I am not sure it is well implemented.The Registration flow is as follow:
User chooses an Alias -> Details Alias + userID (Device's Universally Unique Identifier) are sent server side
If Alias is available, ApiKey(token) is generated, User registered and sent back client side (Stored in DB)
Services.js
(function(angular) {
myApp.factory("deviceDB.Service", ['$resource', '$http', '$q',
function ($resource, $http , $q ) {
return {
//Second Promsie : After API token is generated server-side, store res in db
RegDevice: function (alias, apiKey, userID) {
var deferred = $q.defer();
var configuration ;
var db = window.sqlitePlugin.openDatabase({name: "config.db"});
setTimeout(function () {
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS user_details (userID UNIQUE , alias TEXT, apiKey TEXT)');
tx.executeSql("INSERT INTO user_details (userID, alias, apiKey) VALUES (?,?,?)", [userID, alias, apiKey], function (tx, res) {
deferred.resolve(configuration = true);
}, function (e) {
// console.log("ERROR: " + e.message);
deferred.reject(configuration = false);
});
});
}, 1000);
return deferred.promise;
},
//First Promsie: Register user server side & generate APi token
RegUser: function (alias, userID) {
var deferred = $q.defer();
var pro;
pro = $resource('api/query/register', {'alias': alias, 'userID': userID},
{ query: {
isArray: false,
method: 'GET' } });
setTimeout(function () {
pro.query(function (res) {
if (res.error) {
deferred.reject( { error : res.error, exists: res.exists, msg: res.message } );
}
else {
deferred.resolve( {error : res.error , alias: res.alias , apiKey: res.apiKey, msg: res.message } );
}
}, function (e) {
deferred.reject( { errorStatus: e.status } );
});
}, 1000);
return deferred.promise;
}
};
}]);
}(window.angular));
Now, in My controller I would like to chain both promises above. I quote the follwoing from the Documentation :
then(successCallback, errorCallback, notifyCallback) – regardless of when the promise was or will be resolved or rejected, then calls one of the success or error callbacks asynchronously as soon as the result is available. The callbacks are called with a single argument: the result or rejection reason. Additionally, the notify callback may be called zero or more times to provide a progress indication, before the promise is resolved or rejected.
What is the point of having Callbacks if they can fire regardless if the Promise is resolved?
Shouldn't I call for e.g Promise2 within the first Promise's Success Callback? If it is fired regardless of of Promise1 being resolved, How then can I chain Promise2 in a way to fire only when Promise1 is resolved?
What I tried :
Controller.js
myApp.controller('RegisterController', ['$scope', '$http', 'deviceDB.Service',
function ($scope , $http , deviceDB.Service) {
var Promise1 = deviceDB.RegUser($scope.alias, $scope.Device);
// First promise - Validate with server
Promise1.then(function(data)
{
console.log(' Registration Server-Side successfully');
$scope.apiKey = data.apiKey;
term.echo(data.apiKey);
}, function(e)
{
console.log('Registration Failed');
term.echo(e.msg);
})
//Call Promise 2 & Store details Client-Side using .then()
.then(deviceDB.RegDevice($scope.alias, $scope.apiKey, $scope.Device),
function(d){
console.log('Items Stored in DB successfully');
}, function()
{
console.log('Items Stored in DB Failed');
});
}]);
Notes: I understand it is a bad practice to store details client-side, however, i am after a different concept (anonymous messaging) and there is no security concerns..
Thanks for your time
Your second then call seems incorrect, after
//Call Promise 2 & Store details Client-Side using .then()
then takes up-to 3 parameters then(successCallback, errorCallback, notifyCallback) you are passing it: deviceDB.RegDevice($scope.alias, $scope.apiKey, $scope.Device) which is evaluated immediately and the promise returned is passed to the function then as the success function, your success function is passed as the errorCallback and your fail function is passed as the notifyCallback.
I would try the following
Promise1.then(function(data)
{
console.log(' Registration Server-Side successfully');
$scope.apiKey = data.apiKey;
term.echo(data.apiKey);
return deviceDB.RegDevice($scope.alias, $scope.apiKey, $scope.Device)
}, function(e)
{
console.log('Registration Failed');
term.echo(e.msg);
return e;
}).then(function(d) {/*all good*/}, function(e) {/* all bad */}
Notice the call to RegDevice is now within a function block, and a promise is returned from the then block you want to chain from.
I find $q.serial a great library for chaining promises. It's very easy to use and handles a lot of stuff like checking if all promises on the chain are really promises.
Here is a small example:
function do_all() {
var task_1 = function() {
return $http.get("some url")
.then(on_xhr_completed_fn, on_xhr_failed_fn);
}
var task_2 = function(some_data) {
vm.bla = some_data;
return $http.get("other url")
.then(on_xhr_completed_fn, on_xhr_failed_fn);
}
var task_3 = function(other_data) {
vm.bli = other_data;
}
var tasks = [task_1, task_2, task_3];
return $q.serial(tasks)
.then(function() {
console.log("Finished tasks 1, 2 and 3!!!");
});
}
Here's an approach that may be helpful using async/await:
async function run_promise_A(args) {
return new Promise((resolve, reject) => {
return resolve(resolve_value)
});
}
async function run_promise_B(args) {
return new Promise((resolve, reject) => {
return resolve(resolve_value)
});
}
async function run_promise_C(args) {
return new Promise((resolve, reject) => {
return resolve(resolve_value)
});
}
async function run_several_async_functions(userid) {
let a = run_promise_A(userid);
let b = run_promise_B(a);
let c = run_promise_C(b);
return c;
}
return Promise.resolve()
.then(() => {
let c = (async () => {
let c = await run_several_async_functions(userid)
return c;
})();
return c;
})
.then((c) => {
return c;
})
.catch((err) => {
console.log(err);
});

Categories

Resources