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
Related
I created an Ionic app with 'ionic start myApp sidemenu', added a login page and now I want to customize my headers style according with the type of user entered in the login, lets say positive class for admins and calm for normal users for example. I've try to change the class from the controller with a variable, but it is not working, here is my code:
app.js:
...
$stateProvider
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'js/app/menu/sideMenu.html',
controller:'appController'
})
...
appController:
.controller('appController', function(sessionService, $scope, $stateParams, $state) {
$scope.ambiente = sessionService.getAmbiente();
console.log('The class is:'+$scope.ambiente);
}
The service sessionService.getAmbiente() returns the name of the class saved after login with window.localStorage, it works fine.
sideMenu.html:
<ion-side-menus>
<ion-side-menu side="left">
<!--**** Using ng-class**** -->
<ion-header-bar ng-class="ambiente"><!--ng-class="ambiente"-->
<h1 class="title">Menu</h1>
</ion-header-bar>
<ion-content>
<ion-list>
...
</ion-list>
</ion-content>
</ion-side-menu>
<ion-side-menu-content>
<!--**** Using an expression**** -->
<ion-nav-bar class={{ambiente}}>
...
</ion-nav-bar>
<ion-nav-view name="menuContent"></ion-nav-view>
</ion-side-menu-content>
</ion-side-menus>
I also tried using a variable in the $rootScope but I think it is not the most proper way and it did not refresh fine when the type of user changed.
Based on the result you get from login
if(user.role == "Admin"){
$rootScope.adminHeader=true;
}
else{
$rootScope.adminHeader=false;
}
Now In your sidemenu.html,Use ng-show for class change
<ion-header-bar class="bar-balanced" ng-show="adminHeader">
<h1 class="title">Menu</h1>
</ion-header-bar>
<ion-nav-bar class="bar-calm" ng-show="!adminHeader">
<h1 class="title">Menu</h1>
</ion-header-bar>
Hope This will help you . Thanks
Not like you your user and data work, especially as I have a service that gives me the user who is logged in or not, and all data in this case will do the following
What you must do is within the "run" define the value of your variable for different roles something like this:
angular.module('starter.controllers', [])
.run(function($window, $rootScope, sessionService) {
var user = sessionService.get('user');
if(user.role == 'Admin'){
$rootScope.adminHeader=true;
}else{
$rootScope.adminHeader=false;
}
})
My sessioService service
.factory('sessionService', ['$http', function($http) {
return {
set: function(key, value) {
return localStorage.setItem(key, JSON.stringify(value));
},
get: function(key) {
return JSON.parse(localStorage.getItem(key));
},
destroy: function(key) {
return localStorage.removeItem(key);
},
};
}])
Html code :
<ion-nav-bar ng-class="positive : adminHeader, other_class : !adminHeader">
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
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"
}
}
})
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
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)