I am new to angular and trying to setup a login system. I have some 'buttons' setup to redirect users to an Oauth prompt to users facebook/google account when the button is clicked. My problem is that the function to log users in is executing immediately on page log and not when the button is clicked.
I am pretty sure the root lies in the way JS objects work but I am still learning angularjs and it is a bit confusing.
I believe that putting the functions on the $scope will execute them immediately but I don't see how else I can expose them to the ng-click.
Could someone help me work out how to make the buttons work as expected?
template:
<ion-view title="Account">
<ion-nav-buttons side="right">
<button menu-toggle="right" class="button button-icon icon ion-navicon"></button>
</ion-nav-buttons>
<ion-content class="has-header padding">
<h1 ng-click="google_login()">Log in with Google</h1>
<h1 ng-click="fb_login()">Log in with Facebook</h1>
<h1 ng-click="dev_login()">Dev login</h1>
<div id="logs"></div>
<form class="list">
<label class="item item-input">
<input type="text" placeholder="Username" ng-model="user.username" required>
</label>
<label class="item item-input">
<input type="password" placeholder="Password" ng-model="user.password" required>
</label>
<div class="padding">
<button class="button button-block button-stable" ng-click="email_authenticate()">Login</button>
</div>
</form>
</ion-content>
</ion-view>
controller:
.controller('AccountCtrl', function($scope, $state, Authentication) {
$scope.dev_login = Authentication.dev_authenticate(); //executes immediately
$scope.fb_login = Authentication.fb_authenticate(); //executes immediately
$scope.google_login = Authentication.google_authenticate(); //executes immediately
$scope.email_login = Authentication.email_authenticate(); //executes immediately
$scope.logout = Authentication.logout();
});
These are defined in services.js:
.factory('Authentication', function ($http) {
return {
authenticate: function () {
return $http({
url: 'https://api.squawkfinace.com/authenticate',
method: 'post'//,
//data: {facebook_authtoken: key}
});
},
fb_authenticate: function () {
return $.oauth2({
//Oauth details
}, function (token, response) {
localStorage.setItem("LoggedInAccount", JSON.stringify({'platform': 'facebook', 'token': token}));
console.log(token);
$state.transitionTo("app.notifications");
}, function (error, response) {
// do something with error object
});
},
google_authenticate: function () {
return $.oauth2({
//oauth details
}, function (token, response) {
localStorage.setItem("Account", JSON.stringify({'platform': 'google', 'key': token}));
}, function (error, response) {
// do something with error object
$("#logs").append("<p class='error'><b>error: </b>" + JSON.stringify(error) + "</p>");
$("#logs").append("<p class='error'><b>response: </b>" + JSON.stringify(response) + "</p>");
});
},
dev_authenticate: function () {
return null;
},
email_authenticate: function () {
return null;
},
logout: function () {
localStorage.removeItem("Account");
return null;
}
}
});
It's because you're actually executing the functions
$scope.dev_login = Authentication.dev_authenticate();
should be
$scope.dev_login = Authentication.dev_authenticate;
The first scenario executes the function and assigns the result to $scope. You want to assign the reference to the function instead.
Related
This question already has answers here:
Why are Callbacks from Promise `.then` Methods an Anti-Pattern
(2 answers)
Closed 5 years ago.
I am adding a simple todo list to my ionic vs1/angularjs project.
I want to use the ionic modal to launch this list. Since I need to launch it from everywhere I looked for a way to do this.
I found this article https://medium.com/#saniyusuf/create-an-isolate-modal-with-ionic-v1-b4cf73f05727 which had me create a factory that could be launched from any controller. Love it!
Problem is, it's a todo list where users need to be able to add/delete.
I want to save this information to firebase so I created a factory to hold all the firebase crud operations for the ToDo list.
So I now have a factory that launches the modal and one that has the firebase crud operations.
In the modal launcher I figured out how to include the crud operations so that the buttons would interact. Problem is how do I get the value of the input.
Modal Launcher
angular.module('formulaWizard')
.factory('IsolateModal', IsolateModal)
IsolateModal.$inject = ['$rootScope', '$ionicModal', '__ToDo',
'$window'];
function IsolateModal($rootScope, $ionicModal, __ToDo, $window) {
var modalsIsolateScope = $rootScope.$new();
var currentUser = $rootScope.currentUser || JSON.parse($window.sessionStorage.getItem('payload'));
var isolateModal = {
open: open
};
function open() {
$ionicModal.fromTemplateUrl(
'app/to-do/toDo.html',
{
scope: modalsIsolateScope
}
)
.then(function (modalInstance) {
modalsIsolateScope.close = function () {
closeAndRemove(modalInstance);
},
modalsIsolateScope.add = function(){
addTodo(modalInstance);
};
return modalInstance.show();
});
}
function closeAndRemove(modalInstance) {
return modalInstance.hide()
.then(function () {
return modalInstance.remove();
});
}
function addTodo(modalInstance) {
var i = modalInstance
__ToDo.toDo($scope.input)
.then(function(result) {
$scope.input = {};
// Reload our todos, not super cool
getAllTodos();
});
}
return isolateModal;
}
My Data Factory
angular.module('formulaWizard')
.factory('__ToDo', function(__Refs, $q) {
return {
toDo: function(id, userObject, cb) {
var toDo = __Refs.userNotes.child(id).push(userObject);
__Refs.userNotes.child(id).child(newToDo.key()).update({ toDo_id:
newToDo.key() }).then(function(response) {
cb(response);
}, function(e) {
console.error('error occured');
});;
},
updateToDo: function(userId, toDoId, userObject, cb) {
var x =
__Refs.userNotes.child(userId).child(toDoId).update(userObject)
.then(function(response) {
cb(response);
}, function(e) {
console.error('Error editing');
});
},
deleteToDo: function(userId, toDoId, cb) {
__Refs.userNotes.child(userId).child(toDoId).remove(function(error) {
if (error) {
console.error(error);
} else {
cb();
}
});
},
getuserNotes: function(id, cb) {
__Refs.userNotes.child(id).on('value', function(response) {
cb(response.val());
});
}
}
});
Call From Controller
$scope.openModal = function () {
IsolateModal.open();
};
Html
<ion-modal-view>
<ion-header-bar class="bar-stable">
<h1 class="title">My List</h1>
<button class="button icon ion-close-round button-icon"
ng-click="close()"></button>
</ion-header-bar>
<ion-content>
<div class="list card" style="width:100%; margin-left:0;">
<div class="item item-body">
<div class="item-input-inset">
<label class="item-input-wrapper">
<input id="newInput" type="text" placeholder="New Todo"
ng-model="input.name">
</label>
<button class="button button-balanced button-small" ng-click="add()">
Add Todo
</button>
</div>
<ion-list can-swipe="true">
<ion-item ng-repeat="item in todos">
{{item.name}}
<ion-option-button class="button-assertive" ng-click="deleteTodo(item.id)">
Delete
</ion-option-button>
</ion-item>
</ion-list>
</div>
</div>
</ion-content>
</ion-modal-view>
How can I get the input value from the html page into the factory?
Thanks
how do I get the value of the input?
Return the promise:
function open() {
̲r̲e̲t̲u̲r̲n̲ $ionicModal.fromTemplateUrl(
'app/to-do/toDo.html',
{
scope: modalsIsolateScope
}
)
.then(function (modalInstance) {
modalsIsolateScope.close = function () {
closeAndRemove(modalInstance);
},
modalsIsolateScope.add = function(){
addTodo(modalInstance);
};
return modalInstance.show();
});
}
Then extract the returned value from the promise:
$scope.openModal = function () {
var promise = IsolateModal.open();
promise.then(function(value) {
console.log(value);
});
return promise;
};
I'm implementing facebook login and its working alright with angular.but the problem is when i get the data from facebook i'm unable to put in a textfield. when i put it in an alert its able to give me the data but can't put it in a textfield.
<div ng-controller="facebook_login">
<p align="center"><button class="icon icon-left ion-social-facebook button button-positive button-small" ng-click="fbLogin()">Sign Up with Facebook</button></p>
<div class="list">
<div class="item">
<label class="item item-input item-stacked-label">
<span class="input-label">Fashion Line</span>
<input type="text" ng-model="email" ng-value="{{data.email}}" />
<div>
JS
.controller('facebook_login',['$scope', '$ionicModal', '$timeout', 'ngFB', function($scope, $ionicModal, $timeout, ngFB) {
$scope.fbLogin = function () {
ngFB.login({scope: 'email,public_profile,publish_actions'}).then(
function (response) {
if (response.status === 'connected') {
//alert('Facebook login succeeded, got access token: ' + response.authResponse.accessToken);
//$scope.closeLogin();
ngFB.api({
path: '/me',
params: {fields: 'first_name,last_name,gender,email,picture'}
}).then(
function (data) {
$scope.facebook = data;
alert(data.email)
$scope.email = $scope.data.email;
document.getElementById("email").innerHTML = data.email;
});
} else {
alert('Facebook login failed');
}
});
};
}])
Seems like you never defined $scope.data but you're trying to use it. Did you mean $scope.facebook.email instead?
I am working with a form and I literally just want to get the value from an ng-model. the form looks like this:
<form name="comment_form" class="row" novalidate>
<div class="col col-80 content col-center">
<input class="new-comment-message" type="text" style="margin-left: 15px;" placeholder="Leave a comment..." ng-model="new_comment" required></input>
</div>
<div class="col col-20 button-container col-center">
<button class="button button-clear send" type="submit" ng-click="addComment()" ng-disabled="comment_form.$invalid">
Send
</button>
</div>
</form>
This is my whole controller. The end result is to post a comment to wordpress however With my form content returning undefined its a bit difficult. (P.S. its posting to wordpress and the comment is just saying 'undefined'):
.controller('EasternInnerCtrl', function ($http, $timeout, $scope, $ionicLoading, $stateParams, $ionicScrollDelegate, $cordovaSocialSharing, $ionicModal, Easternc, AuthService) {
$scope.eastc = Easternc.get($stateParams.eastcId);
$ionicModal.fromTemplateUrl('commenter.html', {
scope: $scope,
animation: 'slide-in-up'
}).then(function(modal) {
$scope.modal = modal
})
$scope.openModal = function() {
$scope.modal.show()
}
$scope.closeModal = function() {
$scope.modal.hide();
};
$scope.$on('$destroy', function() {
$scope.modal.remove();
});
$scope.addComment = function(){
$ionicLoading.show({
template: 'Submiting comment...'
});
console.log($scope.new_comment);
Easternc.submitComment($scope.eastc.id, $scope.new_comment).then(function(data){
if(data.status=="ok"){
var user = AuthService.getUser();
var comment = {
author: {name: user.data.username},
content: $scope.new_comment,
date: Date.now(),
user_gravatar : user.avatar,
id: data.comment_id
};
console.log($scope.new_comment);
/*$scope.eastc.comments.push(comment);
console.log(comment);
$scope.new_comment = "";
$scope.new_comment_id = data.comment_id;
$ionicLoading.hide();
$ionicScrollDelegate.scrollBottom(true);*/
}
});
};
$scope.sharePost = function(link){
console.log(link);
window.plugins.socialsharing.share('I just read this article on blah: ', null, null, url);
};
})
my console log is showing: undefined when I click send though?
I'm pretty sure the modal got an isolated scope. It means $scope.new_comment wont exists in your controller.
You should try this :
$scope.addComment = function(comment){
Easternc.submitComment($scope.eastc.id,comment).then(function(data){
console.log(comment);
});
};
with this in your html
<button class="button button-clear send" type="submit" ng-click="addComment(new_comment)" ng-disabled="comment_form.$invalid">
Send
</button>
Hope it helped.
I am calling two functions on ng-click. But it doesn't work. I am not sure why the Refresh1() is not called when I cross-checked through debugger.
HTML CODE
<div class="row" ng-controller="PublishManifestCtrl">
<div class="col-xs-12 col-md-12">
<div class="widget">
<div class="widget-header bordered-bottom bordered-themeprimary">
<i class="widget-icon fa fa-tasks themeprimary"></i>
<span class="widget-caption themeprimary">Manifest Status</span>
</div>
<div class="widget-body">
<form class="form-bordered" role="form">
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last published to agents on <b>{{manifeststatus.manifestLastPublishedDate}}</b>.</label>
</div>
<div class="form-group">
<label style="padding-left: 8px;">Manifest was last updated by <b> {{manifeststatus.lastUpdatedByUser}} </b> on <b>{{manifeststatus.manifestLastedUpdatedDate}}</b>.</label>
</div>
<div class="form-group">
<div class="col-sm-offset-1">
**<button id="PublishButton" class="btn btn-default shiny " ng-disabled="manifeststatus.enablePublishButton" ng-click="Save(manifeststatus);Refresh1()">Publish</button>**
</div>
<br/>
<div id="statusDivPublish" ng-show="showstatus">
<alert type="{{alert.type}}">{{alert.msg}}</alert>
</div>
</div>
</form>
</div>
JSFILE
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
}
$scope.Refresh1 = function () {
//refresh
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
}
});
new code
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.Refresh1();
}
$scope.Refresh1 = function ($rootScope, $state, $stateParams) {
debugger;
return {
restrict: 'AC',
link: function (scope, el, attr) {
el.on('click', function () {
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
});
}
};
};
});
The first one updates and displays a successfull message, while the second function refreshes the page.
use this
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
call refresh inside the first function and remove it from the ng-click.
Update
You have a different type of problem i had it too. you try to refresh a state inside a method, it's really difficult i solve that problem with this snippet
if($state.current.name == /*name of the current state*/) {
$state.go($state.current, {}, {reload: true});
$modalInstance.close();
}
else {
$modalInstance.close();
$state.go(/*name of the current state*/);
}
it's not difficult but it didn't behave like you have understand it.
UPDATE
taking your code
$scope.Refresh1 = function () {
//refresh
$state.go($state.current, {}, {reload: true});
}
What about calling refresh inside of save in $http handler ?
Like this:
$http.post($rootScope.WebApiURL + '/updatemanifeststatus')
.then(function(){
$scope.Refresh1();
});
Don't execute two function in one ng-click, instead add the Refresh1 call to the end of the Save call, like so.
HTML
<button id="PublishButton"
class="btn btn-default shiny "
ng-disabled="manifeststatus.enablePublishButton"
ng-click="Save(manifeststatus)">Publish</button>
JS
$scope.Save = function (data) {
debugger;
$http.post($rootScope.WebApiURL + '/updatemanifeststatus');
//$http.get({ url: $rootScope.WebApiURL + '/getmanifeststatus' });
$scope.manifeststatus = data;
$scope.showstatus = true;
$scope.alert = { type: 'success', msg: 'Published Successfully.' };
$(".statusDivPublish").show();
$scope.refresh();
}
Update
If you are using AngularJS V1.2.2 or higher, then using ui-router, the following should work to reload the data.
$state.transitionTo($state.current, $stateParams, {
reload: true,
inherit: false,
notify: true
});
The shortest way to accomplish this though would be with:
$state.go($state.current, {}, {reload: true}); //second parameter is for $stateParams
Its also worth noting that none of these will actually reload the page. If you want to reload the state AND the page, there is no ui-routermethod for it. Do window.location.reload(true)
Update 2
If you are receiving:
$state is not defined at Scope.$scope.Refresh1
(publishmanifest.js:44) at Scope.$scope.Save (publishmanifest.js:37)
at $parseFunctionCall (angular.js:12345) at angular-touch.js:472 at
Scope.$eval (angular.js:14401) at Scope.$apply (angular.js:14500) at
HTMLButtonElement. (angular-touch.js:471) at
HTMLButtonElement.n.event.dispatch (jquery.min.js:3) at
HTMLButtonElement.r.handle (jquery.min.js:3)
You are not injecting the $state service in your controller. You must do this in order to use it.
//without annotation (inferred, not safe when minifying code)
function Controller($scope, $state) {...}
//inline annotation
module.controller('Controller', ['$scope','$state', function($scope, $state) {...}]);
//$inject property annotation
function Controller($scope, $state) {...}
Controller.$inject = ['$scope', '$state'];
Pick one of the methods above to setup your controller to use $state.
Just make a third function like:
function3(data) {
save(data);
refresh1();
}
I'm trying to automatically reload my side menu after I log in and log out. I'm doing that by checking my window.localStorage. I've experienced that the side menu won't reload/refresh after I do the action login or logout.
I'm using $state.go('tabs.home') to navigate to another page, but my side menu won't refresh.
Below here is my code:
navCtrl:
app.controller('NavCtrl', function ($scope, $ionicSideMenuDelegate, $rootScope) {
$scope.showMenu = function () {
$ionicSideMenuDelegate.toggleLeft();
};
$scope.showRightMenu = function () {
$ionicSideMenuDelegate.toggleRight();
};
var data = JSON.parse(window.localStorage.getItem("currentUserData"));
if (data != null) {
if (data["id_gebruiker"] == null) {
$rootScope.control = {
showLogin: false,
showLogout: true
};
}
else {
$rootScope.control = {
showLogin: true,
showLogout: false
};
}
}
})
navHtml:
<ion-side-menu-content ng-controller="NavCtrl">
<ion-nav-bar class="bar-positive">
<ion-nav-back-button class="button-icon ion-arrow-left-c">
</ion-nav-back-button>
<ion-nav-buttons side="left">
<button class="button button-icon button-clear ion-navicon" ng-click="showMenu()">
</button>
</ion-nav-buttons>
<ion-nav-buttons side="right">
<button class="button button-icon button-clear ion-ios7-gear" ng-click="showRightMenu()">
</button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-nav-view animation="slide-left-right"></ion-nav-view>
</ion-side-menu-content>
loginCtrl:
app.controller('LoginCtrl', function ($scope, $http, $state) {
/*
* This method will be called on click event of button.
* Here we will read the email and password value and call our PHP file.
*/
$scope.check_credentials = function () {
//document.getElementById("message").textContent = "";
$http({ method: 'GET', url: 'http://localhost:34912/api/gebruikers?email=' + $scope.email + '&wachtwoord=' + $scope.wachtwoord }).success(function (data) {
bindUserData(data);
//window.location.reload();
$state.go('tabs.about');
});
function bindUserData(data) {
//alert(JSON.stringify(data));
window.localStorage.setItem("currentUserData", JSON.stringify(data));
}
}
});
app.controller('LogoutCtrl', function ($scope, $http, $state) {
/*
* This method will be called on click event of button.
* Here we will read the email and password value and call our PHP file.
*/
$scope.logout = function () {
var data = JSON.parse(window.localStorage.getItem("currentUserData"));
if (data != null) {
window.localStorage.removeItem("currentUserData");
$state.go('tabs.home');
}
}
});
loginHtml:
<ion-view title="Login">
<ion-content>
<form id="loginForm" ng-app="ionicApp" ng-controller="LoginCtrl">
<div class="list">
<label class="item item-input">
<span class="input-label">Email</span>
<input ng-model="email" type="text" placeholder="Username" />
</label>
<label class="item item-input">
<span class="input-label">Wachtwoord</span>
<input ng-model="wachtwoord" type="password" placeholder="***********" />
</label>
</div>
<div class="padding">
<input type="submit" value="Log on" ng-click="check_credentials()" class="button button-block button-positive" />
</div>
</form>
</ion-content>
I hope you'll understand my problem. I also tried to do a window.location.reload() before $state.go, but that looks buggy. Are there some best practices to fix my problem? Please help me!
Greetings.
Look at the accepted solution at https://stackoverflow.com/a/30524540/1376640
Relevant part of the code is:
$scope.logout = function () {
$ionicLoading.show({
template: 'Logging out....'
});
$localstorage.set('loggin_state', '');
$timeout(function () {
$ionicLoading.hide();
$ionicHistory.clearCache();
$ionicHistory.clearHistory();
$ionicHistory.nextViewOptions({
disableBack: true,
historyRoot: true
});
$state.go('login');
}, 30);
};
Worked for me.
Not a Angular expert but I think that your page will have rebuilt before the $http.get has finished. I got round this by raising an event so where you call bindUserData in the get success change that to $scope.$emit('event', data) then handle the update in a $scope.$on('event'. data). Cut down version of my code below.
controller('AppCtrl', function($scope, $ionicModal, $timeout, MenuData, Data, $ionicActionSheet, UserData, $state, SessionStorage) {
$scope.$on('menuDataChange', function (event, data) {
//refresh menu items data
$scope.items = data;
//clear the state
$state.go($state.current, {}, { reload: true });
});
$scope.items = Data.getItems(SessionStorage.isAuthenticated());
// Form data for the login modal
$scope.loginData = {};
$scope.doLogout = function () {
SessionStorage.clear();
$scope.$emit('menuDataChange', Data.getItems(false)); //Get the menu items for unauthenticated users and raise the change event
};
// Perform the login action when the user submits the login form
$scope.doLogin = function () {
console.log('Doing login', $scope.loginData);
UserData.async($scope.loginData.username, $scope.loginData.password, '12345').then(
// successCallback
function () {
data = UserData.getAll();
var expirationDate = new Date();
expirationDate.setTime(new Date().getTime() + 1200000); //20 minutes
SessionStorage.save({ serverAuthToken: data.d.Items[0].ServerAuthToken, expirationDate: expirationDate });
$scope.$emit('menuDataChange', Data.getItems(true)); //get the menu items for authenticated users and raise the change event
console.log(data);
$state.go('app.home', {}, { reload: true });
},
// errorCallback
function () {
console.log('userdate error');
},
// notifyCallback
function () { }
);
};
})