How to use firebase "ref" inside a controller - ionic-framework

I made a factory in service.js file
angular.module('app.services', [])
.factory('Auth', function($firebaseAuth){
var ref = new Firebase('https://loginmy-reddit.firebaseio.com');
return $firebaseAuth(ref);
})
.service('BlankService', [function(){
}]);
I want to use the ref for logging out the user which is in my main.js file
angular.module('app')
.controller('MainCtrl',function($scope,$state,Auth){
$scope.login = function(authMethod){
Auth.$authWithOAuthPopup(authMethod).then(function(authdata){
console.log(authdata);
$scope.signedInUser = authdata;
$state.go('menu.home');
}).catch(function(error){
console.log(error);
})
}
$scope.logout=function(){
ref.unauth();
//state.go('main');
}
How can i logout the user retaining the ref in service.js file..

You can extend your current service a bit like this:
.factory('Auth', function($firebaseAuth){
var ref = new Firebase('https://loginmy-reddit.firebaseio.com');
return {
login: function(){
return $firebaseAuth(ref);
},
logout: function () {
ref.unauth()
}
}
})
And use it in your controller like this:
$scope.login = function(authMethod){
Auth.login().$authWithOAuthPopup(authMethod).then(function(authdata){
console.log(authdata);
$scope.signedInUser = authdata;
$state.go('menu.home');
}).catch(function(error){
console.log(error);
})
}
$scope.logout=function(){
Auth.logout();
//state.go('main');
}

Related

What does this `checkSession` function do?

I have included the firebase and angularfire libraries to my ionic framework project.
I am following the below link for my sample project.
https://www.sitepoint.com/creating-firebase-powered-end-end-ionic-application/
I am not able to understand how the 'checkSession' function in the below 'app.js' works. Could someone please explain?
How can we call the 'auth' function which is inside 'checkSession' function?
app.js
angular.module('bucketList', ['ionic', 'firebase', 'bucketList.controllers'])
.run(function($ionicPlatform, $rootScope, $firebaseAuth, $firebase, $window, $ionicLoading) {
$ionicPlatform.ready(function() {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if (window.StatusBar) {
StatusBar.styleDefault();
}
$rootScope.userEmail = null;
$rootScope.baseUrl = 'https://bucketlist-app.firebaseio.com/';
var authRef = new Firebase($rootScope.baseUrl);
$rootScope.auth = $firebaseAuth(authRef);
$rootScope.show = function(text) {
$rootScope.loading = $ionicLoading.show({
content: text ? text : 'Loading..',
animation: 'fade-in',
showBackdrop: true,
maxWidth: 200,
showDelay: 0
});
};
$rootScope.hide = function() {
$ionicLoading.hide();
};
$rootScope.notify = function(text) {
$rootScope.show(text);
$window.setTimeout(function() {
$rootScope.hide();
}, 1999);
};
$rootScope.logout = function() {
$rootScope.auth.$logout();
$rootScope.checkSession();
};
$rootScope.checkSession = function() {
var auth = new FirebaseSimpleLogin(authRef, function(error, user) {
if (error) {
// no action yet.. redirect to default route
$rootScope.userEmail = null;
$window.location.href = '#/auth/signin';
} else if (user) {
// user authenticated with Firebase
$rootScope.userEmail = user.email;
$window.location.href = ('#/bucket/list');
} else {
// user is logged out
$rootScope.userEmail = null;
$window.location.href = '#/auth/signin';
}
});
}
});
})

nightwatch custom command callback

I'm trying to create a custom command in nightwatch that runs a query on a Postgres database and returns the result. The query runs just fine and outputs the result to the console but then the execution of the test stops. I don't understand how callbacks work. How can I fix this custom command?
exports.command = function(sql, callback) {
var self = this;
var pg = require('pg');
var conString = self.globals.testinfo.connectionString;
var db = new pg.Client(conString);
db.connect(function(err) {
if(err) {
console.error('could not connect', err);
}
else {
db.query(sql, function(err, result) {
if(err) {
console.log('error running query', err);
}
else {
console.log(result.rows.length);
db.end();
}
});
}
}),
function(result) {
if (typeof callback === 'function') {
callback.call(self, result);
}
}
return this;
};
I had to wrap the database connection in a perform command to get this working. I'm not sure if this is the best way to handle the callback, but it works. Here's the updated version of the custom command:
exports.command = function(sql,callback) {
var self = this;
var pg = require('pg');
var cs = self.globals.testinfo.connectionString;
self.perform(function(self,done) {
pg.connect(cs,function(err,db,done) {
if(err) {
return console.error(err);
}
db.query(sql, function(err,result) {
done();
if(err) {
return console.error(err);
}
console.log(result.rows.length);
callback(result.rows[0]);
});
});
pg.end();
done();
});
};
Here's how I call the custom command in the test:
browser.myCustomCommand('select * from table limit 1;', function(row) {
browser.assert.deepEqual(row.column,'some value');
});
Can you try this:
exports.command = function(sql, callback) {
var self = this;
var pg = require('pg');
var conString = self.globals.testinfo.connectionString;
var db = new pg.Client(conString);
var cb= function(result) {
if (typeof callback === 'function') {
callback.call(self, result);
}
};
db.connect(function(err) {
if(err) {
console.error('could not connect', err);
cb(false);
}
else {
db.query(sql, function(err, result) {
if(err) {
console.log('error running query', err);
cb(false);
}
else {
console.log(result.rows.length);
db.end();
cb(true);
}
});
}
}),
return this;
};
And in your test :
'test' : function(browser){
browser.yourCommandName(sql,function(result){
console.log(result); //if connect is good result would be true and false if fail to connect.
});
}
Ps: the result in callback can be as an object(contain rows or anything you want), instead of boolean only in this example.
And Nightwatch is used for end-to-end testing, it is not aimed for Database testing,i think you should find another framework to test database connection.

How to set up profiles and sessions in Firebase and Ionic using Facebook Auth

I am very new to Firebase and struggling to set up a system where a user logs in via Facebook, and his/her profile picture is saved in a database.
I have a users and also a uids array in Firebase. What I want the flow to be is:
Login via Facebook
Store some memory of the user so they don't have to login again on the app, or perhaps store into the uids and users array
Get the existing name, location to fill into a profile section of the app
Update any of these to then fill into the Firebase users database, as well as add new fields e.g. location
Here is my current setup:
Login Controller:
.controller('LoginCtrl', ['Auth', '$state', '$location', '$scope', '$rootScope', '$firebaseAuth', '$window',
function (Auth, $state, $location, $scope, $rootScope, $firebaseAuth, $window) {
// check session
//$rootScope.checkSession;
// Create a callback to handle the result of the authentication
$scope.user = {
email: this.email,
password: this.password
};
$scope.validateUser = function (user) {
$rootScope.show('Please wait.. Authenticating');
console.log('Please wait.. Authenticating');
var email = this.user.email;
var password = this.user.password;
/* Check user fields*/
if (!email || !password) {
$rootScope.hide();
$rootScope.notify('Error', 'Email or Password is incorrect!');
return;
}
/* All good, let's authentify */
Auth.$authWithPassword({
email: email,
password: password
}).then(function (authData) {
console.log(authData);
//$rootScope.userEmail = user.email;
$window.location.href = ('#/app/meals');
$rootScope.hide();
}).catch(function (error) {
console.log("Login Failed!", error);
if (error.code == 'INVALID_EMAIL') {
$rootScope.notify('Invalid Email Address');
}
else if (error.code == 'INVALID_PASSWORD') {
$rootScope.notify('Invalid Password');
}
else if (error.code == 'INVALID_USER') {
$rootScope.notify('Invalid User');
}
else {
$rootScope.notify('Oops something went wrong. Please try again later');
}
$rootScope.hide();
//$rootScope.notify('Error', 'Email or Password is incorrect!');
});
};
$scope.loginWithGoogle = function () {
Auth.$authWithOAuthPopup('google')
.then(function (authData) {
$state.go($location.path('app/meals'));
});
};
$scope.loginWithFacebook = function () {
Auth.$authWithOAuthPopup('facebook')
.then(function (authData) {
console.log(authData);
$state.go($location.path('app/meals'));
})
.catch(function(error){
if (error.code === "TRANSPORT_UNAVAILABLE") {
Auth.$authWithOAuthRedirect("facebook").then(function (authData) {
// User successfully logged in. We can log to the console
// since we’re using a popup here
console.log(authData);
$state.go($location.path('app/meals'));
});
} else {
// Another error occurred
console.log(error);
}
});
};
}
])
Key functions like get session I want in $rootScope:
.run(function ($ionicPlatform, $rootScope, $firebaseAuth, $firebase, $window, $ionicLoading) {
$ionicPlatform.ready(function () {
// Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
// for form inputs)
if (window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if (window.StatusBar) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
$rootScope.userEmail = null;
$rootScope.baseUrl = 'https://[myappurl.firebaseio.com/';
var authRef = new Firebase($rootScope.baseUrl);
$rootScope.auth = $firebaseAuth(authRef);
$rootScope.authData = authRef.getAuth();
$rootScope.show = function(text) {
$rootScope.loading = $ionicLoading.show({
content: text ? text : 'Loading..',
animation: 'fade-in',
showBackdrop: true,
maxWidth: 200,
showDelay: 0
});
};
$rootScope.hide = function() {
$ionicLoading.hide();
};
$rootScope.notify = function(text) {
$rootScope.show(text);
$window.setTimeout(function() {
$rootScope.hide();
}, 1999);
};
$rootScope.logout = function() {
authRef.unauth();
$rootScope.authDataCallBack;
};
$rootScope.checkSession = function() {
if ($rootScope.authData) {
console.log("User " + authData.uid + " is logged in with " + authData.provider);
$rootScope.userEmail = user.email;
$window.location.href = ('#/app/meals');
} else {
console.log("No session so logout");
$rootScope.userEmail = null;
$window.location.href = '#/auth/signin';
}
}
$rootScope.authDataCallBack = function(authData) {
if ($rootScope.authData) {
console.log("User " + authData.uid + " is logged in with " + authData.provider);
} else {
console.log("User is logged out");
$window.location.href = '#/auth/signin';
}
};
});
})
The profile page:
<ion-view view-title="Profile">
<ion-content class="has-header">
<div class="list card">
<div class="item">
<h2>{{user.name}}</h2>
<p>{{user.city}}</p>
</div>
<!--https://github.com/israelidanny/ion-profile-picture-->
<!--<div class="item item-body">-->
<!--<img src="http://graph.facebook.com/{{user.id}}/picture?width=270&height=270"/>-->
<!--</div>-->
</div>
</ion-content>
</ion-view>
Auth factory:
app.factory('Auth', ['rootRef', '$firebaseAuth', function (rootRef, $firebaseAuth) {
return $firebaseAuth(rootRef);
}]);
If it helps, here is my SignUpCtrl which pushes items into the users array and also stores an array of uids of users already set up in the app.
.controller('SignUpCtrl', [
'$scope', '$rootScope', '$firebaseAuth', '$window', 'Auth',
function ($scope, $rootScope, $firebaseAuth, $window, Auth) {
$scope.user = {
firstname: this.firstname,
lastname: this.lastname,
email: "",
password: ""
};
$scope.createUser = function () {
var firstname = this.user.firstname;
var lastname = this.user.lastname;
var email = this.user.email;
var password = this.user.password;
if (!email || !password) {
$rootScope.notify("Please enter valid credentials");
return false;
}
$rootScope.show('Please wait.. Registering');
$rootScope.auth.$createUser(
{email: email, password: password})
.then(function (user) {
console.log('user is created');
$rootScope.hide();
$rootScope.userEmail = user.email;
var usersRef = new Firebase('https://foodsharingapp.firebaseio.com/users');
var keyRef = usersRef.push({
'uid': user.uid,
'email': email,
'firstname': firstname,
'lastname': lastname
});
var uidRef = new Firebase('https://[myapp].firebaseio.com/uids/' + user.uid + '/' + keyRef.key());
uidRef.set({'registered': true});
$window.location.href = ('#/app/meals');
}, function (error) {
console.log('error unfortunately');
$rootScope.hide();
if (error.code == 'INVALID_EMAIL') {
console.log('invalid email');
$rootScope.notify('Invalid Email Address');
}
else if (error.code == 'EMAIL_TAKEN') {
console.log('email taken');
$rootScope.notify('Email Address already taken');
}
else {
console.log('not sure what happened');
$rootScope.notify('Oops something went wrong. Please try again later');
}
});
}
Questions:
I want to call $rootScope.authDataCallBack(authData) on any controller to get the name and any details of the user_id logged in, however this is not working. Am I thinking about this right? How can I use my $rootScope functions as ways to obtain global information?
When I log in I see the Facebook object appearing fine, should I use the Facebook ID as a uid to store in my array?
On any view, how can I use the session uid or authData to then match against my list of users in the user array and pull out more detailed user info? Is there some pseudocode I can use and would this be in every function in my controller, or would it be split between factory and controller?

No Data from Service to Controller to Scope -> Result Undefined Angularjs Ionic

My problem is, that the controller just send an undefiend and not the data from http of service. I inspect it with chrome. I am new at ionic. By calling the AppSqliDBFactory.getMasterdataId() method, it shows an undefiend, also at the scope variable.
.controller('ReadMasterdataCtrl', function ($scope, $state, $ionicNavBarDelegate, MasterdataService, AppSqliDBFactory){
$scope.masterdataId;
$scope.masterdataData;
AppSqliDBFactory.getMasterdataId().then( function (masterdata){
$scope.masterdataId = masterdata[0].masterdataId;
}).catch(function (err){
console.log(err);
});
//here is the error -> no data at "$scope.masterdataData = masterdata;"
MasterdataService.getMasterdataDB($scope.masterdataId)
.then(function (masterdata) {
$scope.masterdataData = masterdata;
console.log("getMasterdataDB respont");
console.log($scope.masterdataData);
}).catch(function (err) {
console.log(err);
});
})
//Service
.factory('MasterdataService', function ($q, $http, SERVER_URL) {
//Create JSON Object
var srv = {};
//Array for JSON Objects
srv.masterdata = [];
srv.getMasterdataDB = function (masterdataId) {
var deferred = $q.defer();
var masterdata;
var masterdataId = masterdataId;
var baseUrl = 'xxxx';
$http.get(SERVER_URL + baseUrl + masterdataId).success(function (response){
masterdata = response[0];
console.log(masterdata);
return deferred.resolve(masterdata);
}).error(function (err){
return deferred.reject(err);
});
return deferred.promise;
//return srv.getMasterdata();
};
// Public API
return {
getMasterdataDB: function ( masterdataId) {
return $q.when(srv.getMasterdataDB( masterdataId));
}
};
});
Simplified:
AppSqliDBFactory.getMasterdataId().then(function (masterdata) {
$scope.masterdataId = masterdata[0].masterdataId;
});
MasterdataService.getMasterdataDB($scope.masterdataId).then(function (masterdata) {
$scope.masterdataData = masterdata;
});
When MasterdataService.getMasterdataDB() is called, AppSqliDBFactory.getMasterdataId() may not have been resolved yet, so $scope.masterdataId can be undefined (which is probably what is happening in your case).
You have to call AppSqliDBFactory.getMasterdataId() after AppSqliDBFactory.getMasterdataId() has been resolved:
AppSqliDBFactory.getMasterdataId().then(function (masterdata) {
$scope.masterdataId = masterdata[0].masterdataId;
MasterdataService.getMasterdataDB($scope.masterdataId).then(function (masterdata) {
$scope.masterdataData = masterdata;
});
});
Or with chaining:
AppSqliDBFactory.getMasterdataId().then(function (masterdata) {
$scope.masterdataId = masterdata[0].masterdataId;
return MasterdataService.getMasterdataDB($scope.masterdataId);
}).then(function (masterdata) {
$scope.masterdataData = masterdata;
});

smart way to rewrite this function

I have this, and I am showing a div if user clicked one button and not showing it if the user clicked other. Its working but its dumb to do this way with repeatition
$j(document).ready(function() {
$j('#Button1').click( function () {
var data = $j("form").serialize();
$j.post('file.php', data, function(response){
$j("#Response").show();
});
});
$j('#Button21').click( function () {
var data = $j("form").serialize();
$j.post('file.php', data, function(response){
//do something else
});
});
});
I'd do it by adding a class to the selected buttons and then pull the event.target id from the click function:
$j('.buttons').click(function(e) {
var buttonId = e.target.id,
data = $j("form").serialize();
$j.post('file.php', data, function(response) {
switch (buttonId) {
case "Button1":
$j("#Response").show();
break;
case "Button21":
//do something else
break;
}
});
});
You need to abstract the data from the functionality.
sendClick('#Button1', function() {
$j('#Response').show();
});
sendClick('#Button21', function() {
// do something
});
sendClick function
function sendClick(selector, callback)
{
$j(selector).click( function () {
var data = $j("form").serialize();
$j.post('file.php', data, callback);
});
}
This way you can repeat the same functionality over and over by changing the selector and the callback. You could customise this even further by:
function sendClick(selector, options, callback)
{
// handle arguments
if(typeof options == 'function') {
callback = options;
options = {};
} else {
options = options || {};
}
$j.extend({
form: 'form',
file: 'file.php'
}, options);
// abstracted logic
$j(selector).click(function() {
var data = $j(options.form).serialize();
$j.post(options.file, data, callback);
});
}
then use like
sendClick('#select', {form: '#anotherForm'}, function() {
// do something
});
or
sendClick('#another', function(response) {
// something else
});
You can attach the event to both, and then, when you need to check which element triggered the event, use event.target.
$j(function() {
$j('#Button1, #Button2').click( function (event) {
var data = $j("form").serialize();
$j.post('file.php', data, function(response){
if ($(event.target).is('#Button1')) {
$j("#Response").show();
} else {
// Do something else
}
});
});
});
Here are two different ways:
You can combine the two handlers into one handler:
$j(document).ready(function () {
$j('#Button1, #Button21').click(function() {
var id = this.id;
var data = $j("form").serialize();
$j.post('file.php', data, function(response) {
if (id == 'Button1') {
// Show
} else {
// Do something else
}
});
});
});
Or write a special kind of handler:
$j.fn.clickAndPost = function (handler) {
this.click(function () {
var me = this;
var data = $j("form").serialize();
$j.post('file.php', data, function(response) {
handler.call(me);
});
});
});
...and attach two of them:
$j(document).ready(function () {
$j('#Button1').clickAndPost(function () {
// Show
});
$j('#Button21').clickAndPost(function () {
// Do something else
});
});
$j(function($) {
$('#Button1', '#Button21').click(function() {
var that = this,
data = $('form').serialize();
$.post('file.php', data, function(response) {
if ( that.id === 'Button1' ) {
$('#Response').show();
} else {
//do something else
}
});
});
});
$(document).ready(function() {
$('#Button1 #Button21').click(function() {
var that = this.attr("id");
data = $('form').serialize();
$.post('file.php', data, function(response) {
if ( that === 'Button1' ) {
$('#Response').show();
} else {
//do something else
}
});
});
});
Let me know if it's not working.