I'm developping an ionic application and when using angular for login my controller is called twice,
I've looked through all the others similar questions but didn't find a solution .
The problem is even when I remove the ng-controller="LoginCtrl as lgnCtrl"
I get my controller called once but without two-way databinding.
here is my route file :
$stateProvider
.state('login', {
url: "/login",
views: {
'main': {
templateUrl: "app/user/loginView.html",
controller: "LoginCtrl",
controllerAs: "lgnCtrl"
}
}
})
$urlRouterProvider.otherwise('/login');
here is my controller
angular.module('starter.controllers')
.controller('LoginCtrl', LoginCtrl);
function LoginCtrl($state, $storage, $translate, $ionicPopup, LoginService, messageService) {
var lgnCtrl = this;
console.log("user dash 1zz");
return lgnCtrl;
}
and here is my views:
loginView.html :
<ion-view view-title="loginView" id="signinBlk">
<ion-content>
<div class="list list col span_1_of_2 " ng-controller="LoginCtrl as lgnCtrl">
</div>
</ion-content>
</ion-view>
index.html:
<body ng-app="starter">
<ion-nav-view name="main"></ion-nav-view>
</body>
if you already define your controller in route you dont need to define controller in html template remove the ng-controller attribute with value form html template then run it will run just once
Instead of having this
ng-controller="LoginCtrl as lgnCtrl"
in html, we can have this in the controller when the route is defined with a controller, for example in the controller, it will go like this
$routeProvider
.when("/", { templateUrl: "views/abc.html", controller: "LoginCtrl as lgnCtrl", caseInsensitiveMatch: true });
it worked like a charm
the functions in the controller are only called once.
Related
I'm building an AngularJS application with angular-ui-router to handle my routing.
I'm wondering if it's possible to seperate the login functionality and it's template completely from the ng-view directive, so the rest of my layout isn't shown before the user have been authenticated.
This is the current setup:
Any ideas on how to do this?
Thanks in advance!
Yeah using Ui-Router declare create a different state like this :
.state('login', {
url: '/login',
controller: 'LoginController',
templateUrl: 'app/views/login.html',
})
.state('stateNameIfLoggedIn', {
url: '/dashboard',
controller: 'DifferentController',
templateUrl: 'app/views/differentTemplate.html',
userLoggedIn: true
})
In your LoginController check if the user is currently login redirect him to different state like this:
//controller code starts
if(userLoggedIn === true){
$state.go('stateNameIfLoggedIn')
}
The thing is that with the routeProvier before show the route with the template + controller you can check something and then control the route.
'use strict'
intranet
.config ($routeProvider) ->
$routeProvider
.when '/page1',
templateUrl: 'views/page1.html'
controller: 'Page1Ctrl'
.when '/page2',
templateUrl: 'views/page2.html'
controller: 'Page2Ctrl'
.otherwise
redirectTo: '/'
.run ($rootScope,Token,$location) ->
$rootScope.$on '$locationChangeStart', ->
Token.check()
$rootScope.active_menu = $location.path()
My token provider with check the token.
'use strict'
intranet
.provider 'Token', ->
#$get = ($location,$http,$q,$rootScope) ->
check: ()->
if localStorage['access_token']
$rootScope.loginMade = true
else
$rootScope.loginMade = false
$location.path '/login'
And that's my index for show or not the content.
<header-app></header-app>
<sidebar-app></sidebar-app>
<!-- Add your site or application content here -->
<div ng-view="" class="container" ng-class="{container_login : loginMade == false}">
</div>
<footer-app></footer-app>
I have the following Index.html file (I put div with ng-view as well):
<ul ng-controller="myController">
<li>
Do it!
</li>
</ul>
routes config:
$routeProvider.when('/doit', {
templateUrl: 'partials/doit.html'
controller: 'myController'
});
$routeProvider.otherwise({
redirectTo: 'index.html'
});
Controller:
app.controller('myController', ['$scope', '$location', function ($scope, $location) {
$scope.name = "name";
alert($scope.name);
$location.path("/");
}]);
The weird thig is that after I click on the Do it! link, it goes to http://localhost:3000/#/doit.html (the code of myController executes after the click, I see the alert pop-up), and then I go back to http://localhost:3000/#/index.html (this is what I want, I put $location.path("/") in the controller.
However, this time, for some reason, the controller code doesn't execute. It only runs after I refresh the page, even though it is assigned to the unordered list. Could anyone help please?
Your routes config should be something like:
$routeProvider.
when('/', {
templateUrl: '/index.html',
controller: 'homeCtrl'
}).
when('/doit', {
templateUrl: 'partials/doit.html',
controller: 'myController'
}).
otherwise({
redirectTo: '/'
});
and you do not need to specify controller name at two places i.e. in the partial and in your route config, specifying at the config level should be sufficient.
The doit view should be the one which is loaded in the ng-view tag as it is a state of your application.
I've been creating a contact list website and have just begun trying to implement an add contact function. So far I have created the page using a form and input elements and then use ng-click to call a function which theoretically would add an object containing these input values into an already-existing array in the controller. For some reason this doesn't work and nothing is added.
In particular, I'm having trouble with the js/app.js file and the $scope.saveContact = function() in relation to the partial/edit.html webpage. Clicking the "Confirm button" when trying to add a contact calls the saveContact function, but the results are not stored properly. Any help is appreciated.
In my HTML I have this code (which calls the saveContact() function in my controller.
<a href="#/"><div class="confirm col-xs-6" ng-click="saveContact()">
<h3>Confirm</h3>
</div></a>
In my app.js file I have a declaration of an empty object and an array containing objects that already have values (used to display the contacts that are already created). I'm trying to add to these contacts using .push() but it for some reason it doesn't work.
$scope.contact = { ... } //empty object that gets inputs from HTML
$scope.contacts = [ { ... }, ... ];
$scope.saveContact = function(){
$scope.contacts.push($scope.contact);
};
This bottom function fails to push the contact object to the contacts array and I don't understand why.
This is happening as you have assigned same controller to all your routes. Your saveContact function is working fine, its pushing the object to the array. As soon as the route changes, a new instance of the controller is created and hence the added object is lost. You should create a service(singleton) to store the object and inject the service as a dependency to the controller. In this way the array will persist until the page load.
app.service("storeContact", function(){
var contacts = [];
this.setContact = function(cnt){
contacts.push(cnt)
};
this.getContact = function(){
return contacts;
}
});
And inject it in the controller and use the setContact and getContact methods to update the contact array and retrieve the contact array.
Ideally, you should have separate controllers for your route.
The issue is in your app.config code. You are using the same controller for all your templates.
This is not required since you have already mentioned the same in ng-controller attached with body
<body ng-controller="AppController">
<div ng-view></div>
<script src="js/app.js"></script>
</body>
Using same controller for all your routes is essentially (re)instantiating the controllers when the route is changed and thats the reason why $scope.contacts.push($scope.contact); is ineffective for the route / when called from /add.
contactListApp.config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
controller: 'AppController',
controllerAs: 'list',
templateUrl: 'partials/list.html'
})
.when('/add', {
controller: 'AppController',
controllerAs: 'add',
templateUrl: 'partials/edit.html'
})
.when('/edit/:id', {
controller: 'AppController',
controllerAs: 'edit',
templateUrl: 'partials/edit.html'
})
.otherwise({
redirectTo: '/'
});
}]);
Workaround:
Either use separate controllers for separate routes and use a service to store the object
OR
Simply remove the controller and controller as from your route config and you are good to go.
Updated config:
contactListApp.config(['$routeProvider', '$locationProvider',
function($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: 'partials/list.html'
})
.when('/add', {
templateUrl: 'partials/edit.html'
})
.when('/edit/:id', {
templateUrl: 'partials/edit.html'
})
.otherwise({
redirectTo: '/'
});
}]);
Original Question
I'm developing a mobile app using the Ionic Framework and AngularJS and I am having issues with controllers not reloading once they have been initialised.
One of the state transitions (from 'app.postbox-details' to 'app.audit-questions') should pass a parameter to the 'app.audit-questions' controller but this controller does not update itself with the new parameter because it isn't reloading.
Code Example
app.js file - config
angular.module('sf-maintenance', ['ionic', 'starter.controllers', 'starter.services', 'ngCordova'])
.config(function ($stateProvider, $urlRouterProvider, $httpProvider) {
$stateProvider
.state('home', {
url: '/home',
templateUrl: 'templates/home.html',
controller: 'HomeCtrl',
})
.state('app', { //app state being the side-menu
url: '/app',
abstract: true, //means that this state will never be activated directly, users will always go to a child state instead.
templateUrl: 'templates/side-menu.html',
controller: 'MenuCtrl'
})
.state('app.postbox-details', {
url: '/postbox-details',
views: {
'menuContent': {
templateUrl: 'templates/postbox-details.html',
controller: 'PostboxDetailsCtrl'
}
}
})
.state('app.audit-questions', {
url: '/audit-questions/:postboxGuid',
views: {
'menuContent': {
templateUrl: 'templates/audit-questions.html',
controller: 'AuditCtrl'
}
}
})
$urlRouterProvider.otherwise('/home');
});
controller.js file (left out the code that isn't relevant)
angular.module('starter.controllers', [])
.controller('HomeCtrl', function ($scope) {
})
.controller('MenuCtrl', function ($scope) {
})
.controller('PostboxDetailsCtrl', function ($scope, $ionicLoading, $ionicPopup, $cordovaBarcodeScanner, $state, DataService) {
$scope.postboxGuid = DataService.getNewGUID();
//Rest of the controller functions are below
})
.controller('AuditCtrl', function ($scope, $ionicSlideBoxDelegate, $stateParams, DataService) {
$scope.auditDetails = {
postboxGuid: $stateParams.postboxGuid
};
});
View - navigation code
The view code to perform the navigations all use <a> tags:
From the home view to the postbox-details view: <a class="button button-block button-dark icon-right ion-chevron-right" href="#/app/postbox-details">New inspection</a>
From the postbox-details view to audit-questions view: <a class="button button-block button-dark icon-right ion-chevron-right" ng-click="saveFormData()"
ng-href="#/app/audit-questions/{{postboxGuid}}">New audit</a>
So does anybody know how to get controllers to reload once it has been initialised or if I am going about this problem the wrong way could you guide me to a method that will work?
Updated Information
I recently saw a related question and the response by #Radim Köhler pointed to the answer in this question which provides good information on why it may not be a good idea to use cache:false on a view because of performance.
I thought I would share this because in some situations you may benefit more performance-wise by using one of Ionic's built-in view life cycle events to run code without having to disable the view from being cached.
Views are standard cached in ionic. The caching can configured in the view or stateprovider.
http://ionicframework.com/docs/api/directive/ionNavView/
I would like to dynamically change the ui-view attribute such as each time the attribute changes, the view changes too...
I use multiple views as follow:
$stateProvider.state('main',
{url: "/main",
views: {
'': { templateUrl: "partials/main", controller: "MainCtrl" },
'clients#main': {templateUrl: "partials/client-list", controller: "ClientListCtrl"},
'impexp#main': {templateUrl: "partials/imp-exp", controller: "ImpExpCtrl"}
}
}
);
In my MainCtrl I define a $scope variable as follow:
$scope.main_view = 'clients';
and my HTML/jade:
div(ng-attr-ui-view='{{ main_view }}'
The problem is that when I change dynamically $scope.main_view, my view doesn't change.
Is it possible to dynamically change a ui-view? if it is, how?
StateProvider (possibly app.js)
$stateProvider
.state('main', {
url: "/main",
templateUrl: "partials/main.html",
controller: 'MainCtrl'
})
.state('main.substate', {
url: "/", // Inherits /main from parent state
templateUrl: "partials/client-list.html",
controller: 'ClientListCtrl',
});
Any template will be loaded into <div ui-view>
HTML Example:
<!-- Add your site or application content here -->
<div ng-include="'../views/main-nav.html'" ng-controller="NavCtrl"></div>
<div id="main" ui-view=""></div><!-- end #main -->
<div ng-include="'../views/footer.html'"></div>
Events to trigger state change:
<a ui-sref="main.substate">Changes out template and controller</a>
<span ng-click="$state.go('main.substate')">Clicking this will change template</span>
Checkout the ui-router $state docs.