I have registered for hardware back button event registerBackButtonAction inside my controller and using $destroy event to unregister the event. But the event is not getting called when I navigate to different page (state). What am I missing?
.controller('HomeCtrl', function($scope, $ionicPlatform, $location, $rootScope, $http) {
// Register hardware back button
var deregister = $ionicPlatform.registerBackButtonAction(function (event) {
navigator.app.exitApp();
return;
}, 100);
console.log('scope on');
$scope.$on('$destroy', function() {
console.log('destroy called');
deregister();
})
})
In console I dont see destroy called. Please help me fix this.
Update:
In the browser when I navigate from Home to Login the elements of Home still exist in the browser. I guess that is the reason why destroy is not getting called. So the question is should I fire the event manually or should be Home page be actually destroyed when I move to Login?
Here is my index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet">
<link href="css/ionic.app.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- Push notification -->
<script src="js/PushNotification.js"></script>
<!-- Geo location -->
<script type="text/javascript" src="http://maps.google.com/maps/api/js?v=3&sensor=false&language=en"></script>
<!-- app js -->
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
</head>
<body ng-app="starter" ng-controller="AppCtrl">
<ion-nav-view></ion-nav-view>
</body>
</html>
The page are loaded as part of state via template in app.js:
.state('app.login', {
url: "/login",
views: {
'menuContent': {
templateUrl: "templates/login.html",
controller: 'LoginCtrl'
}
}
})
.state('app.home', {
url: "/home",
views: {
'menuContent': {
templateUrl: "templates/home.html",
controller: 'HomeCtrl'
}
}
})
Thanks for the help guys. In my framework the elements of first loaded page are not removed hence $destroy is not called. The workaround is to use the event $ionicView.leave to deregister, so instead of
$scope.$on('$destroy', deregister);
use:
$scope.$on('$ionicView.leave', deregister);
Complete code:
.controller('HomeCtrl', function($scope, $ionicPlatform, $location, $rootScope, $http) {
// Register hardware back button
var deregister = $ionicPlatform.registerBackButtonAction(function (event) {
navigator.app.exitApp();
return;
}, 100);
$scope.$on('$ionicView.leave', deregister);
})
I was supposed to wrap deregister() in an anonymous function. Then it worked for me.
var deregister = $ionicPlatform.registerBackButtonAction(function () {
$state.go('app.start');
}, 100);
$scope.$on('$ionicView.leave', function () {
deregister();
});
This Work for me
var deregister = null;
$scope.$on('$ionicView.enter', function(){
deregister = $ionicPlatform.registerBackButtonAction(
function () {
navigator.Backbutton.goHome(function() {
console.log('hidden');
}, function() {
navigator.app.exitaApp();
});
}, 100
);
})
$scope.$on('$ionicView.leave', function () {
deregister();
});
Related
I am learning AngularJS and I have a problem with the controller.
This example below already worked, but it suddenly stoped without any changes that could cause that. I am not sure what is wrong.
The /templates/index.html file does not load.
This is my main index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Todolist</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<!-- ANGULAR JS -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/1.0.3/angular-ui-router.min.js"></script>
<script src="app/app.js"></script>
<script src="app/controllers/todolists.js"></script>
</head>
<body ng-app="app">
<div ui-view></div>
</body>
</html>
This is my app.js:
var app = angular.module('app', ['ui.router']);
app.config(function ($stateProvider) {
$stateProvider
.state('/', {
url: "/",
templateUrl: "app/templates/index.html",
controller: 'todolists',
});
});
This is my todolists controller:
var app = angular.module('app');
var controllers = {};
console.log("test");
controllers.todolists = function ($scope, $http) {
console.log("test1");
$http.get('http://localhost:8888/todolist/rest/entries/index.json').
then(function(response) {
console.log(response.data);
$scope.data = response.data;
});
};
app.controller(controllers);
console.log("test") writes to console, but console.log("test1") does not, so the controller is not accessed.
Please take a look and let me know if you have and tips about what could be wrong.
Thanks, Grega
You need to register a name for the controller is the problem. Ive registered the name 'todolistCtrl' which is the first argument needed for the controller registration method. the second argument is the function controllers.todolists.
you can then reference todolistCtrl within you State Provider.
controller
var controllers = {};
console.log("test");
controllers.todolists = function ($scope, $http) {
$http.get('http://localhost:8888/todolist/rest/entries/index.json').
then(function(response) {
console.log(response.data);
$scope.data = response.data;
});
};
angular.module('app')
.controller('todolistCtrl', controllers.todolists);
app
var app = angular.module('app', ['ui.router']);
app.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('/', {
url: "/",
templateUrl: "index.html",
controller: 'todolistCtrl',
});
});
Plunker
Example
I know a little bit about Angularjs (I'm still learning) and now I want to learn Ionic too. I tried to have same structure approach for code organization, but it seems that I don't know how to make same code works on Ionic. Can someone helps me, I will write my code first and then explain what is the problem.
index
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title></title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
</head>
<body ng-app="starter">
<ion-nav-view></ion-nav-view>
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="cordova.js"></script>
<script src="app/application.js"></script>
<script src="app/controllers/userDataCtr.js"></script>
</body>
</html>
app
angular.module('starter', ['ionic'])
.run(function($ionicPlatform) {
$ionicPlatform.ready(function() {
if(window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
cordova.plugins.Keyboard.disableScroll(true);
}
if(window.StatusBar) {
StatusBar.styleDefault();
}
});
})
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/home',
controller: 'userDataCtr',
templateUrl: 'app/views/home.html'
})
;
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/home');
});
controller
(function() {
'use strict';
angular
.module('starter')
.controller('userDataCtr', userDataCtr);
userDataCtr.$inject=['$state','$window'];
function userDataCtr($state,$window) {
var vm = this;
vm.test = test;
function test() {
vm.testing = "Does work?";
}
}
})();
home view
<div ng-init="userDataCtr.test()">{{testing}}</div>
When I start application I get nothing on screen, blank page. It seems like function is not even started. Does anyone know where I'm wrong?
Thanks
Edit:
Now I figure out that if I change this:
(function() {
'use strict';
angular
.module('starter')
.controller('userDataCtr', userDataCtr);
userDataCtr.$inject=['$state','$window'];
function userDataCtr($state,$window) {
var vm = this;
vm.test = test;
function test() {
vm.testing = "Does work?";
}
}
})();
to this:
(function() {
'use strict';
angular
.module('starter')
.controller('userDataCtr', userDataCtr);
userDataCtr.$inject=['$state','$window','$scope'];
function userDataCtr($state,$window,$scope) {
$scope.test - function() {
$scope.testing = "Does work?";
}
}
})();
Works !!
But I don't want to use $scope. Does anyone knows why first solution fail and another works?
I followed this link https://developers.google.com/identity/sign-in/web/sign-in to get Google Signin on Angular-based website.
I have seen some weird behavior. The signin button sometimes show but not always. When I refresh a page, only 1 in 5 refreshes, the button appears.
I tried in Chrome and Safari and both has same behavior.
Code:
index.html
<script src="https://apis.google.com/js/platform.js" async defer></script>
<meta name="google-signin-client_id" content="my_client_id">
login.html
<div class="g-signin2" data-onsuccess="onSignIn"></div>
login.js
angular.module('app').controller('LoginCtrl', function($scope) {
window.onSignIn = function(googleUser) {
// Get some info
}
});
My guess is that the platform.js script waits for the DOM-ready event and then looks for your div with the "g-signin2"-class. Though, in Angularjs things work a little different. The reason that it works sometimes, is because sometimes your div has been rendered by Angular and sometimes is hasn't been rendered before the Dom-ready event.
There's documentation on how to get the same result with your own javascript.
I made an example that follows your routing.
<!doctype html>
<html lang="en" ng-app="app">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div ng-view></div>
<script src="https://apis.google.com/js/platform.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<script src="https://code.angularjs.org/1.4.6/angular-route.min.js"></script>
<script>
angular.module('app',['ngRoute'])
.config(['$routeProvider',function($routeProvider){
$routeProvider
.when('/log-in', {
template: '<button ng-click="logInCtrl.onLogInButtonClick()">Log In</button>',
controller: 'LogInController',
controllerAs: 'logInCtrl'
}).otherwise({
redirectTo:'/log-in'
});
}])
.controller('LogInController',function(){
var self = this; //to be able to reference to it in a callback, you could use $scope instead
gapi.load('auth2', function() {//load in the auth2 api's, without it gapi.auth2 will be undefined
gapi.auth2.init(
{
client_id: 'CLIENT_ID.apps.googleusercontent.com'
}
);
var GoogleAuth = gapi.auth2.getAuthInstance();//get's a GoogleAuth instance with your client-id, needs to be called after gapi.auth2.init
self.onLogInButtonClick=function(){//add a function to the controller so ng-click can bind to it
GoogleAuth.signIn().then(function(response){//request to sign in
console.log(response);
});
};
});
});
</script>
</body>
</html>
Or as a directive:
<!doctype html>
<html lang="en" ng-app="app" ng-controller="MainController">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<google-sign-in-button on-sign-in="onSignIn(response)" g-client-id="CLIENTID.apps.googleusercontent.com"></google-sign-in-button>
<script src="https://apis.google.com/js/platform.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<script>
angular.module('app',[])
.controller('MainController',['$scope', function ($scope) {
$scope.onSignIn=function(response){
console.log(response);
}
}])
.directive('googleSignInButton',function(){
return {
scope:{
gClientId:'#',
callback: '&onSignIn'
},
template: '<button ng-click="onSignInButtonClick()">Sign in</button>',
controller: ['$scope','$attrs',function($scope, $attrs){
gapi.load('auth2', function() {//load in the auth2 api's, without it gapi.auth2 will be undefined
gapi.auth2.init(
{
client_id: $attrs.gClientId
}
);
var GoogleAuth = gapi.auth2.getAuthInstance();//get's a GoogleAuth instance with your client-id, needs to be called after gapi.auth2.init
$scope.onSignInButtonClick=function(){//add a function to the controller so ng-click can bind to it
GoogleAuth.signIn().then(function(response){//request to sign in
$scope.callback({response:response});
});
};
});
}]
};
});
</script>
</body>
</html>
After writing the previous examples I found a better and easier way to implement it. With this code you inherit the same button as you normally would.
<!doctype html>
<html lang="en" ng-app="app" ng-controller="MainController">
<head>
<meta charset="UTF-8">
<title>Document</title>
<meta name="google-signin-client_id" content="CLIENTID.apps.googleusercontent.com">
</head>
<body>
<google-sign-in-button button-id="uniqueid" options="options"></google-sign-in-button>
<script src="https://apis.google.com/js/platform.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.6/angular.min.js"></script>
<script>
angular.module('app', [])
.controller('MainController', ['$scope',
function($scope) {
//for more options visit https://developers.google.com/identity/sign-in/web/reference#gapisignin2renderwzxhzdk114idwzxhzdk115_wzxhzdk116optionswzxhzdk117
$scope.options = {
'onsuccess': function(response) {
console.log(response);
}
}
}
])
.directive('googleSignInButton', function() {
return {
scope: {
buttonId: '#',
options: '&'
},
template: '<div></div>',
link: function(scope, element, attrs) {
var div = element.find('div')[0];
div.id = attrs.buttonId;
gapi.signin2.render(div.id, scope.options()); //render a google button, first argument is an id, second options
}
};
});
</script>
</body>
</html>
I found another way to solve the problem a liitle bit simply.
The explanation from #sniel is perfect but I will let you know more simple solution.
you can use below sample code very simiraliry with using $watch
https://developers.google.com/identity/sign-in/web/build-button
<!-- html part -->
<div id="signInButton"></div>
//gapi is Asynchronously loaded so you need to watch
$scope.$watch('gapi', function(newValue,oldVale){
if(newValue !== oldVale){
if(gapi){
gapi.signin2.render('signInButton',
{
'onsuccess': $scope.onSuccess,
'onfailure': $scope.onFailure,
'scope':'https://www.googleapis.com/auth/plus.login'
}
);
}
}
});
I am a newbie in angularjs. My intention is to add this angularjs directive https://github.com/720kb/angular-datepicker to my app.js so that I can be able to select dates in one of my views buses.html.
My app.js file looks something like this:
My app.js file looks like this...
var busRest1 = angular.module("busReservator1", ["720kb.datepicker"]);
//dependency injection that fails
var busRest = angular.module("busReservator", ["ionic", "busRest1"]);
busRest.run(function($ionicPlatform, $state) {
$ionicPlatform.ready(function() {
if(window.cordova && window.cordova.plugins.Keyboard) {
cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
}
if(window.StatusBar) {
StatusBar.styleDefault();
}
});
document.addEventListener("resume", function() {
$state.go("home", {}, {location: "replace"});
}, false);
});
busRest.factory('myService', function(){
var savedData = {}
function set(data){
savedData = data;
}
function get(){
return savedData;
}
return {
set: set,
get: get
}
});
busRest.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state("home", {
url: "/home",
templateUrl: "templates/home.html",
controller: "homeCtrl",
})
.state("busList", {
url: "/busList",
templateUrl: "templates/busList.html",
controller: "busListCtrl",
cache: false
})
$urlRouterProvider.otherwise('/home');
});
busRest.controller("homeCtrl", ['$scope', function($scope){
}]);
busRest.controller('busListCtrl', ['$scope', 'myService2', function($scope, myService2) {
//declaring an array of transporters
$scope.transporters = [];
$scope.AddTransporter = function(){
transporters = [document.getElementById('transporter_agency').value, document.getElementById('transporter_vehicleType').value, document.getElementById('transporter_vehicleCapacity').value, document.getElementById('transporter_btnValue').value];
myService2.set(transporters);
};
}]);
busRest.controller('DataCtrl', ['$scope', '$http', function($scope, $http) {
$http.get('js/datafile2.json').success(function (data) {
$scope.artists = data.artists;
$scope.albums = data.albums;
})
}]);
My index.html looks like this
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>Bus Ticket Reservation</title>
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<!-- For the date picker css-->
<link href="src/css/angular-datepicker.css" rel="stylesheet" type="text/css" />
<!-- For the date picker js -->
<script src="src/js/angular-datepicker.js"></script>
<script src="lib/ionic/js/ionic.bundle.js"></script>
<script src="cordova.js"></script>
<script src="js/forge.min.js"></script>
<script src="js/firebase.js"></script>
<script src="js/angularfire.min.js"></script>
<script src="js/app.js"></script>
</head>
<body ng-app="busReservator">
<ion-pane>
<ion-nav-bar class="bar-royal"></ion-nav-bar>
<ion-nav-view ></ion-nav-view>
</ion-pane>
</body>
</html>
When I save and run, the app breaks and the browser window is emptied
I am loading a partial in Angular dependant on the route of the URL.
When I load the partial it loads, and responds to the Controllers functions. However I have a directive which has a watcher. This does not work when I use the
It works fine when I load the HTML inside the main page. I have a Plunker of this here
http://plnkr.co/edit/DK33pIrp0HyhUOjwm5X2?p=preview
Essentially clicking "hello" should change the $scope.origin and the watcher should then fire its event. It does not.
My HTML:
<!DOCTYPE html>
<html ng-app="App">
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<link rel="stylesheet" href="style.css">
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/coffee-script/1.1.2/coffee-script.min.js"></script>
<script src="app.js"></script>
<script src="directive.js"></script>
</head>
<body ng-controller="MapCtrl">
<ng-view></ng-view>
</body>
</html>
app.js
var app;
app = angular.module("App", []);
app.config(function($routeProvider) {
return $routeProvider.when("/", {
templateUrl: "home.html",
controller: MapCtrl
});
});
this.MapCtrl = function($scope) {
return $scope.clicked = function() {
console.log("clicked");
$scope.origin = Math.floor(Math.random() * 11);
return console.log($scope.origin);
};
};
directive.js
(function(angular) {
var app;
app = angular.module("App");
return app.directive("leaflet", function() {
return {
restrict: "E",
replace: true,
transclude: true,
template: "<section id='map' class='map'></section>",
scope: {
origin: "=origin"
},
controller: function($scope, $attrs) {
return $scope.$watch("origin", (function(newValue, oldValue) {
return alert("its changed");
}), true);
}
};
});
})(angular);
home.html
<button ng-click="clicked()">hello</button>
how can I get this working?
edit: I have just made this pure JS and not coffeescript.
Thanks so all who helped me find the issue.
This can be done by setting the
<button ng-click="clicked()">hello</button>
to
<button ng-click="$parent.clicked()">hello</button>
This is because the ng-view will be a child. This simple fix is now working.