Angular reload parent controller on child state change - javascript

I am a newbie to angular JS and IONIC.
I have left side menu:
- Menu 1
- Menu 2
- Menu 3
And right side menu dynamically change based on the selected left menu.
I successfully did this. But, the problem is when i change to other Menu, my right side menu won't be updated before i refresh the page (using F5).
Whats wrong with my code:
controller.js
angular.module('starter.controllers', [])
.controller('AppCtrl', function ($state, $scope, $stateParams) {
var source = $stateParams.source;
$scope.title = source;
$scope.data = {items: []};
if (source == 'Menu1') {
$scope.data.items.push({url: source + '/AAA', label: "AAA"});
$scope.data.items.push({url: source + '/BBB', label: "BBB"});
$scope.data.items.push({url: source + '/CCC', label: "CCC"});
}
if (source == 'Menu2') {
$scope.data.items.push({url: source + '/EEE', label: "EEE"});
}
if (source == 'Menu3') {
$scope.data.items.push({url: source + '/FFF', label: "FFF"});
}
})
.controller('NewsListCtrl', function ($scope, $stateParams) {
})
;
app.js
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: "/app/:source/:channel",
templateUrl: "templates/layout.html",
controller: 'AppCtrl'
})
.state('app.newsList', {
url: "/news-list",
views: {
'menuContent': {
templateUrl: "templates/news-list.html",
controller: 'NewsListCtrl'
}
}
})
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/Menu1/AAA/news-list');
});
layout.html
<ion-side-menus enable-menu-with-back-views="false">>
<ion-side-menu-content>
...
</ion-side-menu-content>
<ion-side-menu side="left">
<ion-content>
<ion-list>
<ion-item menu-close href="#/app/Menu1/AAA/news-list">
AAA
</ion-item>
<ion-item menu-close href="#/app/Menu2/EEE/news-list">
EEE
</ion-item>
<ion-item menu-close href="#/app/Menu3/FFF/news-list">
FFF
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
<ion-side-menu side="right">
<ion-content>
<ion-list>
<ion-item menu-close ng-repeat="item in data.items" href="#/app/{{item.url}}/news-list">
{{item.label}}
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
</ion-side-menus>

Since the parent controller doesn't get re-created when the child state changes, you could have the parent controller listen for $stateChangeSuccess and update the menu based on the state params:
$rootScope.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams){ ... })
https://github.com/angular-ui/ui-router/wiki#state-change-events

Related

Binding the scope with side menu does not work - ionic

I want to show 2 different ion-list on the Menu according to a user "role" in my App.
app.js
.state('app', {
url: '/app',
abstract: true,
cache: false,
templateUrl: 'templates/menu.html',
controller: 'AppCtrl'
})
AppCtrl
.controller('AppCtrl', function($scope) {
// EXAMPLE
$scope.user = {
name: "example",
role: "client"
};
})
menu.html
<ion-list ng-if="user.role == 'manager' ">
<ion-item menu-close href="#/app/search">
MANAGER
</ion-item>
<ion-item menu-close href="#/app/songbook">
ITEM A
</ion-item>
</ion-list>
<ion-list ng-if="user.role == 'client' ">
<ion-item menu-close href="#/app/search">
CLIENT
</ion-item>
<ion-item menu-close href="#/app/search">
ITEM B
</ion-item>
</ion-list>
And the issue is that it does not render any ion-list ! is just empty!
It seems to me that angular is not binding the "scope.user"
Any ideas?
Is your controller' range contains your post html code?
<ion-list ng-if="user.role == 'manager' ">
If the controller includes your list code,
then do you try to avoid array first , like
$scope.user_role == 'manager' in the controller,
ng-if="user.role == 'manager' in the html.
As far as I know ,if you insert a xxx.html into a large controller, using the array like you is correct(if not ,data can bot be reached into the inserted html file)
Anyway. Did you try whether it functions well when you avoid the array, if not, the reason must be the range of angularjs does not reach your post html code

Controller being called twice in Ionic (AngularJS)

In my angular project the user accepts a EULA then get automatically redirected to their dashboard, however, on this redirect the DashboardController seems to be being called twice, the DashboardController is being called on the route itself, I have checked to see if I have accidently called it again in the template but I havn't. Below is my route & controller. It doesn't appear to matter if I access the URL directly or via the redirect on the EULA controller, I get the same result.
The routes
.config(function($httpProvider, $stateProvider, $urlRouterProvider) {
$httpProvider.interceptors.push('httpRequestInterceptor');
$urlRouterProvider.otherwise('/');
$stateProvider
.state('login', {
url: '/',
templateUrl: 'templates/login.html',
data: {
requireLogin: false
}
})
.state('eula', {
url: '/eula',
templateUrl: 'templates/eula.html',
data: {
requireLogin: true
}
})
.state('dashboard', {
url: '/groups',
templateUrl: 'templates/dashboard.html',
data: {
requireLogin: true
}
})
});
The controller:
App.controller('DashboardController', ['$scope', 'RequestService', '$state', '$rootScope', function($scope, RequestService, $state, $rootScope){
alert('test');
}]);
Any ideas?
ADDED MY HTML AS PER COMMENTS
index.html
<body ng-app="App">
<ion-nav-bar class="bar-positive nav-title-slide-ios7" align-title="center">
<ion-nav-back-button class="button-icon ion-arrow-left-c"></ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view class="slide-left-right"></ion-nav-view>
<ui-view></ui-view>
</body>
dashboard.html
<div class="groups" ng-controller="DashboardController">
<ion-view title="App">
<ion-nav-buttons side="right">
<a ui-sref="groupcreate"><span class="icon ion-ios-plus-outline"></span></a>
</ion-nav-buttons>
<ion-content class="padding">
<div class="row">
<div class="col-50" ng-repeat="group in groups">
{{ group }} 1
</div>
</div>
</ion-content>
</ion-view>
</div>
If you are using ui-router you don't have to use ng-controller. You have used it in your dashboard.html, another is generated by ui-router - that's why it is hit twice.
Ok so after a long time debugging and check stuff out, I found out that it was an issue relating to the Nav Bar in ionic, essentially, I was calling <ui-view></ui-view> & <ion-nav-view></ion-nav-view> on the same page, so basically doubling up on my views which in turn was calling the controller twice.
I know this has been answered already as well, but I wanted to add my fix for the exact same problem.
My controllers were also being called twice, but in my case I had to comment out the ng-controller settings in various files:
My config function in the main app.js
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('splash', {
url: "/",
templateUrl: "app/splash/splash.html"
// controller: 'SplashCtrl'
})
Since I was already calling it in the markup:
<ion-view view-title="TickerTags" ng-controller="SplashCtrl as splash">
<ion-content class="splash">
The controller key inside of my Directives
angular
.module('tagsPanelDirective', [])
.controller('TagsPanelCtrl', TagsPanelCtrl)
.directive('tagsPanel', tagsPanel);
function tagsPanel() {
var directive = {
templateUrl: "app/tags/tagsPanel.html",
restrict: "E",
replace: true,
bindToController: true,
// controller: 'TagsPanelCtrl as tagsPanel',
link: link,
scope: false
};
return directive;
function link(scope, element, attrs) {}
}
Again since I was already calling it from within the template markup:
<section class="tags-panel" ng-controller="TagsPanelCtrl as tagsPanel">

Ionic framework ionicView.entered event fired twice

I'm playing with this ionicView events that are fired whenever the views become active, and I'm using the side menu template that you can re-use when creating the project. It seems that if I put a listener for the $ionicView.entered event in the AppCtrl (the one used by the side menu template, which belongs to an abstract state in the ui-router configuration) it gets called twice in a row for any of the subviews (like, when using app.someotherview as a state).
I don't know if this is the expected behavior because from the documentation I would expect it to only fire once, no matter if I change the subview (the menuContent view).
I'd like to know if this is expected behavior and if so, how do I get to have an event fired only once every time it gets to show the side menu template.
This is what I've got written:
This is from the application module:
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "templates/menu.html",
controller: 'AppCtrl'
})
.state('app.overview', {
url: "/overview",
views: {
'menuContent': {
templateUrl: "templates/overview.html",
controller: 'OverviewCtrl'
}
}
})
.state('login', {
url: "/login",
templateUrl: "templates/identificationscreen.html",
controller: "IdentificationCtrl"
})
.state('app.agenda', {
url: "/agenda",
views: {
'menuContent': {
templateUrl: "templates/agenda.html",
controller: 'AgendaCtrl'
}
}
});
$httpProvider.interceptors.push('credentialsInjector');
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/login');
Then the AppCtrl is this:
angular.module('dashboard.controllers.app', [])
.controller('AppCtrl', function($scope, $ionicModal, $timeout, $ionicSideMenuDelegate, authService, $state) {
$scope.logout = function() {
authService.logout();
$state.go('login');
};
$scope.$on('$ionicView.enter', function(){ //This is fired twice in a row
console.log("App view (menu) entered.");
console.log(arguments);
});
$scope.$on('$ionicView.leave', function(){ //This just one when leaving, which happens when I logout
console.log("App view (menu) leaved.");
console.log(arguments);
});
});
The menu template:
<ion-side-menus enable-menu-with-back-views="false">
<ion-side-menu-content edge-drag-threshold="true">
<ion-nav-bar class="bar-stable">
<ion-nav-back-button>
</ion-nav-back-button>
<ion-nav-buttons side="left">
<button class="button button-icon button-clear ion-navicon" menu-toggle="left">
</button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-nav-view name="menuContent"></ion-nav-view>
</ion-side-menu-content>
<ion-side-menu side="left">
<ion-header-bar class="bar-stable">
<h1 class="title">APPoint!</h1>
</ion-header-bar>
<ion-content>
<ion-list>
<ion-item nav-clear menu-close href="#/app/overview">
Overview
</ion-item>
<ion-item nav-clear menu-close href="#/app/agenda">
Agenda
</ion-item>
<ion-item nav-clear menu-close ng-click="logout()">
Logout
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
</ion-side-menus>
A simple workaround is:
$scope.$on('$ionicView.enter', function(ev) {
if(ev.targetScope !== $scope)
return;
// Your code which should only run once
});
The best option that I found to simulate onEnter event was to use in view controller :
$scope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
if (toState.name == "stateName")
doSomething();
}
You can globally disable the caching mechanism used by ionic by doing:
$ionicConfigProvider.views.maxCache(0);
I haven't tried that on my own though.
Else, the best way that worked for me was doing
$scope.$on("$ionicView.afterLeave", function () {
$ionicHistory.clearCache();
});
This is to clear the cache before leaving the view to re-run controller every time you enter back again.
Try $ionicView.afterEnter. That fires only once for me.
URL
At first I used Florian's answer but noticed that in my case it's just a symptom of a root problem, because this doesn't happen to all controllers, just this one.
In my case, it happens because I was trying to incrementally migrate from Ionic/AngularJS v1 to Ionic/AngularJS v2.
I have added controllerAs in my template:
<ion-view view-title="Avatar » Instruments" ng-controller="AvatarInstrumentsCtrl as vm">
but I forgot to remove the controller reference in my app.js :
.state('app.avatar-instruments', {
url: "/avatar/instruments",
views: {
'menuContent': {
templateUrl: "templates/avatar/instruments.html",
controller: 'AvatarInstrumentsCtrl'
}
}
})
So in my case the solution is:
.state('app.avatar-instruments', {
url: "/avatar/instruments",
views: {
'menuContent': {
templateUrl: "templates/avatar/instruments.html"
}
}
})

Angular.js $scope and controller again

I know there are many questions regarding the angular $scope by after a couple of hours I still can't figure out what is wrong. I'm using Angular.js with Ionic but the problem should be angular related.
In my App I need a "add to wishlist" function. In the productDetail view when someone tapps "add to wishlist" I add this product with a service and webSQL to the database. Now when the user goes to the wishlist view I get all saves products but the view doesn't update.
I have a file menu.html with an Ionic side-menu:
<ion-side-menu side="left" expose-aside-when="large" width="72">
<ion-content>
<ion-list ng-controller="LeftMenuCtrl">
<ion-item nav-clear menu-close ng-href="#/app/wish" ng-click="updateWishList()" ng-class="{'current': isActive('/app/wish')}">
<span class="icon icon-menu-wish"></span>
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
The "LeftMenuCtrl" handels the hover for the active menu item.
In my WishListView I would like to show the current added products:
File wishList.html
<ion-view hide-nav-bar="true" view-title="WISHLIST" ng-controller="WishlistCtrl">
<div class="bar bar-header bar-stable">
<div class="header-wrapper">
<!--heading-->
<div class="dash-slider-wrapper"" >
<div class="header-text-main">WHISH</div> <div class="header-text-sub">LIST</div>
</div>
</div>
</div>
<ion-content class="has-header">
<ion-item class="product-card" ng-repeat="product in products">
<div class="card">
EAN: {{product.ean}}
</div>
</ion-item>
</ion-content>
</ion-view>
And the controller:
app.controller("WishlistCtrl", function($scope, $state, productService) {
//gets called when the controller is loaded
productService.getWishlistProducts().then(function (products) {
$scope.products = products;
});
//gets called when the user clicks on the navi but does not
//update the $scope (or it updates the wrong $scope)
$scope.updateWishList = function () {
productService.getWishlistProducts().then(function (products) {
$scope.products = products;
});
};
})
Can anyone tell me whats wrong here please?
Edit:
This is the state for the menu link:
.state('app.wish', {
url: "/wish",
views: {
'menuContent': {
templateUrl: "templates/wish.html"
}
}
})
Edit2:
When I refresh the page, I see all added products. But not immediately. It's like the
$scope.updateWishList = function () ...
creates another $scope...
Edit3:
app.controller('ProductDetailCtrl', function($stateParams ,$state, $scope, productService, $ionicHistory, $ionicPopup) {
$scope.addToWishlist = function(ean) {
productService.addProductToWishlist(ean).then(function(response) {
if(response == "OK") {
var alertPopup = $ionicPopup.alert({
title: 'product added to wishlist',
template: 'You can go to your wishlist to see all your marked products'
});
}
});
};
})
Edit4:
I added a Plunker here: http://plnkr.co/edit/0woPfN
It´s not working but you can see the code there (I deleted unnecessary stuff)
Your problem is that you have 2 declaration of the WishlistCtrl.
Once in the app.js:
.state('app.wish', {
url: "/wish",
views: {
'menuContent': {
templateUrl: "wish.html",
controller: 'WishlistCtrl' //here is the first declaration
}
}
})
Second in the HTML:
<ion-view hide-nav-bar="true" view-title="WISHLIST" ng-controller="WishlistCtrl">
Remove either one and you'll be fine.
Finally, I got it working.
First in the StateProvicer I added a resolve method:
.state('app.wish', {
url: "/wish",
views: {
'menuContent': {
templateUrl: "templates/wish.html",
controller: 'WishlistCtrl',
resolve: {
products: function(productService) {
return productService.getWishlistProducts()
}
}
}
}
})
And to update the model when a new product gets added to the wishlist:
.controller("WishlistCtrl", function($scope, $state, productService, products) {
//set wishlist products on controller load
$scope.products = products;
//updated wishlist when a new product gets added
$rootScope.$on('updatedWishList', function() {
console.log('List has been updated. ');
productService.getWishlistProducts().then(function (products) {
$scope.products = products;
});
});
})
Easy... when you know how :D

Ionic framework $state.go('app.home'); is adding back button on page where I want to go (how to remove it)?

I have app with sidebar menu. I am on second page and I am calling controller function which redirect me to first page using:
$state.go('app.home');
Problem is that on this page is now displayed back button next sidebar menu icon, see image below:
Could somebody tell me how to deny to add back button into pages which has assigned sidebar menu?
Thanks for any help.
app.js is with router config is following:
angular.module('Test', ['ionic', 'config', 'Test', 'LocalStorageModule'])
.run(function($ionicPlatform) {
$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) {
// org.apache.cordova.statusbar required
StatusBar.styleDefault();
}
});
})
.config(function($stateProvider, $urlRouterProvider, localStorageServiceProvider) {
localStorageServiceProvider
.setPrefix('max_relax');
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: 'AppCtrl'
})
.state('app.home', {
url: '/home',
views: {
'menuContent' :{
templateUrl: 'templates/home.html',
controller: 'HomeCtrl'
}
}
})
.state('app.saved', {
url: '/saved',
views: {
'menuContent' :{
templateUrl: 'templates/saved.html',
controller: 'SavedCtrl'
}
}
})
.state('app.settings', {
url: '/settings',
views: {
'menuContent' :{
templateUrl: 'templates/settings.html',
controller: 'SettingsCtrl'
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/home');
});
Edit:
Added menu template:
<ion-side-menus>
<ion-pane ion-side-menu-content>
<ion-nav-bar class="bar-stable">
<ion-nav-back-button class="button-clear"><i class="icon ion-ios7-arrow-back"></i> Back</ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view name="menuContent" animation="slide-left-right"></ion-nav-view>
</ion-pane>
<ion-side-menu side="left">
<header class="bar bar-header bar-stable">
<h1 class="title">Menu</h1>
</header>
<ion-content class="has-header">
<ion-list>
<ion-item nav-clear menu-close href="#/app/home">
Home
</ion-item>
<ion-item nav-clear menu-close href="#/app/saved">
Saved
</ion-item>
<ion-item nav-clear menu-close href="#/app/settings">
Settings
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
</ion-side-menus>
Use $ionicHistory in your controller before calling $state.go('app.home').
.controller('HomeCtrl', function($scope,...,$ionicHistory) {
...
$ionicHistory.nextViewOptions({
disableBack: true
});
$state.go('app.home');
});
You can set nextViewOptions before $state.go('Yourstate'). Like
In your controller, you can write,
$ionicHistory.nextViewOptions({
disableBack: true
});
$state.go('app.home');
So for that transition, it will clear the history stack and sets next view as root of the history stack.
At controller which you want to return HomeCtrl:
.controller('SavedCtrl', function($scope,...,$ionicHistory) {
...
$ionicHistory.nextViewOptions({
disableBack: true
});
$state.go('app.home');
})
.controller('HomeCtrl', function($scope,...,$ionicHistory) {
$ionicHistory.clearHistory();
})
$ionicNavBarDelegate.showBackButton(false);
As long as you have <ion-nav-back-button></ion-nav-back-button> included in <ion-nav-bar> you will see a back button by default on any view using app.
Removing <ion-nav-back-button> will remove the back button from all of the views using app. You can selectively disable it based on what template your viewing by setting hide-back-button="true" on the <ion-view> of that template.
So, in your case, removing <ion-nav-back-button class="button-clear"><i class="icon ion-ios7-arrow-back"></i> Back</ion-nav-back-button> from menu.html will hide the back button on all views using app.
I had this problem too when using Ionic's side menu.
In some cases when selecting an option from the side menu the resulting page/view was showing a back button in the navbar, which it shouldn't (because selecting a menu option should reset the history).
The problem was related to using "ng-click" in the menu option, e.g:
<ion-item menu-close ng-click="showStartPage()" ...>
with 'showStartPage' being a Controller method which calls $state.go(...).
Solution was to code it like this:
<ion-item menu-close href="#/startPage" ...>
When done like this, Ionic is (apparently) able to properly keep track of the navigation history.
(I didn't try it out but probably "ui-sref" instead of "href" would work too)

Categories