Conditionally hide menu button in ionic framework outside <ion-view> - angularjs

In the ionic framework I am trying to hide the menu button conditionally. For other reasons I had to split the menu in its own controller (I don't want to completly re-render the menu and header bar on a refresh), so the header is not in ion-view. I created a watcher on the conditional variable (a stateparam) in the controller of the header. The console log outputs the conditional variable correctly, but the view is not updated (the menu button is always showing).
This is the template:
<ion-side-menus>
<ion-side-menu-content>
<ion-nav-bar class="bar-stable nav-title-slide-ios7">
<ion-nav-back-button ng-if="!isHome" class="button-clear"><i class="icon ion-ios7-arrow-back"></i>Back</ion-nav-back-button>
<button ng-if="isHome" menu-toggle="left" class="button button-icon icon ion-navicon"></button>
<h1 class="title">Title</h1>
</ion-nav-bar>
<ion-nav-view name="menuContent" animation="slide-left-right"></ion-nav-view>
</ion-side-menu-content>
...
</ion-side-menus>
And in the controller:
$scope.$watch(function(){
return $stateParams.contentUrl;
},
function(newVal){
console.log(newVal);
if(!newVal || newVal === 'someParam'){
$timeout(function(){
$scope.$apply(function(){
$scope.isHome = true;
});
console.log("home");
});
} else {
$timeout(function(){
$scope.$apply(function(){
$scope.isHome = false;
});
console.log("not home");
});
}
});
Is there an easier way? Or am I missing something here?

You can use the hide-back-button attribute on the <ion-view> element to declare if that view should hide the back button by default.
http://ionicframework.com/docs/nightly/api/directive/ionView/
<ion-view hide-back-button="true">
<!-- view contents -->
</ion-view>

A kinda dirty workaround would be to give those buttons an id and then use jqlite to hide them like this in the controller:
angular.element(document.querySelector('#back-button')).addClass('hidden');

Setting hide-back-button to false did not work for me. However, in my case the easier solution was to have
<ion-nav-buttons side="left"></ion-nav-buttons>
inside <ion-view>. This is to just include a empty left side nav buttons. This did the trick for me.

It can be done in a easy way:
<ion-side-menus enable-menu-with-back-views = "true">
and on the specific pages where you want to hide the Menu and nav bar, let say your Login Page(inside your login Controller), just type- don't forget to include specified objects inside the controller function.
$scope.$on('$ionicView.beforeEnter', function (event) {
$scope.$root.showMenuIcon = false;
$ionicSideMenuDelegate.canDragContent(false);
});
$scope.$on('$ionicView.beforeLeave', function (event) {
$scope.$root.showMenuIcon = true;
$ionicSideMenuDelegate.canDragContent(true);
});

Related

Model change not getting reflected in view in angularjs

I have got a main index page, in which i initially hide the footer bar. But i want to display it when some item is clicked in some child view. I can see in the logs the model is getting changed, but its not getting reflected in the view.
index page:
<body ng-app="starter">
<ion-pane ng-controller="AudioCtrl">
<ion-nav-bar class="bar-positive">
<ion-nav-back-button>
</ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view></ion-nav-view>
<ion-content></ion-content>
<ion-footer-bar ng-hide="musicBar.hide">
<div class="audio-block">
.....
</div>
</ion-footer-bar>
</ion-pane>
</body>
The child view page:
<ion-view ng-controller="AudioCtrl as controller" title="{{selectedCategory}}">
<ion-content>
<ion-list>
<ion-item ng-repeat="item in items" ng-click="$parent.songClicked()">{{item.desc}}</ion-item>
</ion-list>
</ion-content>
</ion-view>
The angular code:
app.controller('AudioCtrl', function ($sce, $scope) {
$scope.musicBar= {
hide: true
};
$scope.songClicked = function(){
console.log($scope.musicBar.hide);
$scope.musicBar.hide = false;
console.log($scope.musicBar.hide);
};
}
);
When i click the item i can see musicBar.hide changing from true to false, but its not reflected in the view. I have also check other similar questions but the solution doesn't work. I have tried using $scope.$digest() and $scope.$apply(), but then i get apply already in progress.
The index.html and the cub view are each managed by their own instance of AudioCtrl, each having their own scope.
The header is made visible when the main view scope's musicBar.hide becomes true, but that never happens, because the subview doesn't modify it. It modifies the sub view scope's musicBar.hide variable.
I don't see any reason why a sub view would have the same controller as the main view. It shouldn't.

Passing data to ionic popover in ng-repeat

I want to add ionic Popover to my application and place in under ng-repeat however I am struggling a bit with this.
How can I pass a parameter to it?
<p ng-repeat="query in ctrl.timesheet">query.Name<button ng-click="openPopover($event)">Open Popover</button></p>
<script id="my-popover.html" type="text/ng-template">
<ion-popover-view>
<ion-header-bar>
<h1 class="title">My Popover Title</h1>
</ion-header-bar>
<ion-content>
<button ng-click="ctrl.delete(index)">Delete</button>
</ion-content>
</ion-popover-view>
</script>
So in short I want a list of buttons and whenever i click the popover for the button than there is a option to delete the element.
See this demo: http://play.ionic.io/app/eb32466d892c
You can pass scope of your controller to pop over, so whatever you have in parent controller will be available in pop over. Pass a parameter index in openpopover funtion : ng-click = "openPopover($event, pass-index-here)"> and bind it to $scope.index before you open popup, See this:
$ionicPopover.fromTemplateUrl('my-popover.html', {
scope: $scope
}).then(function(popover) {
$scope.popover = popover;
});
$scope.openPopover = function($event,index) {
$scope.index = {'value' : index}; //i am using object, because simple variable shows binding problem some time
$scope.popover.show($event);
};
Now this $scope.index will be available in popover, and will contain latest index of item, which you have clicked because we update its value before opening popover :
<button ng-click="ctrl.delete(index.value)">Delete</button>

Ng-click does not work first time - but works afterwards

I have two states/views called bookmark and bookmarked.
The bookmark view has a button which passes an url into a function called setURL. This function sets the src for the iframe on the bookmarked view.
<ion-view view-title="Bookmarks">
<ion-content>
<button class="button" ui-sref="myLearning.bookmarked" ng-click="setURL('SOMEURL')">Bookmark</button>
</ion-content>
<div class="bar bar-footer bar-assertive"></div>
</ion-view>
The bookmarked view has an iframe whose src is set by the button on the previous view. The src is currently set to nothing because I would never navigate to this view unless I've clicked the bookmark button which would pass in an url.
<ion-view view-title="Bookmarked">
<ion-content>
<iframe id="learningFrame" src="" width="100%" height="100%" seamless></iframe>
</ion-content>
</ion-view>
When I run the app and navigate to the bookmark view and click on the bookmark button, it navigates to the bookmarked view but it displays a blank page in the iframe (src="") rather than using the url passed in from the function. However, from this blank page if I navigate to the bookmarks view and click on the bookmark button the second time, the actual url loads.
Why does it the view not use the url that I have passed in through setURL, on the first load?
This is what the function looks like:
.controller('bookmarkCtrl', function($scope){
$scope.setURL = function(currURL){
document.getElementById('learningFrame').src = currURL;
};
});
I don't know why it does not work the first time...
Any help would be appreciated, thank you.
Instead of doing DOM manipulation from the controller you could simply use ng-src that would have {{}} to have decide src attribute value.
Markup
<ion-view view-title="Bookmarked">
<ion-content>
<iframe id="learningFrame" ng-src="{{learningFrameUrl}}" width="100%" height="100%" seamless></iframe>
</ion-content>
</ion-view>
Controller
.controller('bookmarkCtrl', function($scope){
$scope.setURL = function(currURL){
$scope.learningFrameUrl = currURL;
};
});
Update
As you wanted to share data between you controllers then you could use service/factory component. Then you can use that service by injecting it inside your controller/directive wherever you wanted to use it.
Service
app.service('dataService', function(){
this.learningFrame = {
Url: ''
};
//..other stuff here..//
});
Controller
.controller('bookmarkCtrl', function($scope, dataService){
$scope.setURL = function(currURL){
//this can be available in other controller
//wherever you take value from learningFrameUrl
$scope.learningFrame = dataService.learningFrame;
dataService.learningFrame.Url = currURL;
};
});

ionic / angular 1.3 - Missing ion-nav-back-button when ion-side-menus exist inside view

I can't seem to figure out how to get a back button to appear on a view that contains a ion-side-menus directive.
Here's the absolute simplest example I've come up with:
http://codepen.io/jsplaine/pen/YPxvXL?editors=101.
Note that the ion-views in state x.emptyView and state x.emptySideMenu are children of state x's ion-nav-view.
Here's a more in-depth example, where there exists a side-menu that is actually populated:
http://codepen.io/jsplaine/pen/ZYJRYW?editors=101
Here's the basic router, for the first codepen:
angular.module('ionicApp', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('app', {
url: "/",
templateUrl: "templates/home.html",
controller: 'AppCtrl'
})
.state('x', {
url: "/x",
abstract: true,
template: '<ion-nav-view animation="slide-left-right"/>'
})
.state('x.emptyView', {
url: "/empty-view",
templateUrl: "templates/empty_view_only.html"
})
.state('x.emptySideMenu', {
url: "/empty-side-menu",
templateUrl: "templates/empty_side_menu.html"
})
})
There's a second issue with the more in-depth codepen. Depending on which tab you click first, the 2nd or the 3rd, the corresponding template gets cached for future navigation to BOTH the 2nd and 3rd template. Click the 2nd one first, then the 3rd. Then start over and click the 3rd one first then the 2nd. The fact that this is happening makes me thinking that I'm using ui-router wrong somehow.
I also don't understand why I have to define ion-nav-view in both index.html AND in the abstract state ('x') template. Isn't state 'x' a child of index.html (the empty state)?
Can someone figure out how to modify both codepens so that the back button appears on views containing a ion-side-menus directive, and for the 2nd codepen .. the 2nd and 3rd tab caching issue is resolved?
The solution can be seen here:
http://codepen.io/jsplaine/pen/wBqNmw?editors=101
It seems that ion-side-menus' parent ion-view needs a child ion-nav-bar, and enable-menu-with-back-views must be set to true.
<!-- Side Menu Nav and Burger Defined -->
<script id="templates/side_menu_with_nav.html" type="text/ng-template">
<ion-view view-title="Side Menu with Nav and Burger">
<ion-nav-bar></ion-nav-bar> <!-- HERE -->
<ion-side-menus enable-menu-with-back-views="true">
<ion-side-menu-content>
<ion-nav-bar>
<ion-nav-back-button class="button-icon ion-arrow-left-c"></ion-nav-back-button>
<ion-nav-buttons side="right">
<button class="button button-icon button-clear ion-navicon" menu-toggle="right"></button>
</ion-nav-buttons>
</ion-nav-bar>
....
As the ionic directive/menuToggle docs state: https://github.com/driftyco/ionic/blob/master/js/angular/directive/menuToggle.js#L1
### Button Hidden On Child Views
By default, the menu toggle button will only appear on a root
level side-menu page. Navigating in to child views will hide the menu-
toggle button. They can be made visible on child pages by setting the
enable-menu-with-back-views attribute of the {#link >ionic.directive:ionSideMenus}
directive to true.
I wonder if the authors didn't take your case into account. Their model is a slide-in menu that only slides in partially and can be toggled with a menu icon. So you may be a bit off paradigm but this seemed to work for me albeit a bit lame for duplicating the nav-bar code in the template.
<script id="templates/empty_side_menu.html" type="text/ng-template">
<ion-view view-title="Empty side menu">
<ion-nav-bar align-title="center" class="nav-title-slide-ios7 bar-stable">
<ion-nav-back-button class="button-icon ion-arrow-left-c">
</ion-nav-back-button>
</ion-nav-bar>
<ion-side-menus>
</ion-side-menus>
</ion-view>
</script>

hiding back button in ionic, angularjs

I need to show and hide back button in different pages/views. I took reference from Justin Noel:
<body ng-app="starter" ng-controller="AppCtrl">
<ion-nav-bar class="bar-stable">
<ion-nav-back-button hide-back-button="{{hideBackButton}}">
</ion-nav-back-button>
</ion-nav-bar>
</body>
App controller to toggle button display:
.controller('AppCtrl', function($scope, $location) {
var path = $location.path();
if (path.indexOf('submit') != -1)
$scope.hideBackButton = true;
else
$scope.hideBackButton = false;
})
But this doesnt work as controller is called only once but not at the change of view in different states. Also changing the value of $scope.hideBackButton from other controllers(linked to different states) does not have any effect on the button display.
Can anyone tell me how to toggle back-button display on each navigation. What am I missing here?
I had exactly same problem today.
Simplest solution is to use $ionicNavBarDelegate:
.controller('AppCtrl', function($scope, $location, $ionicNavBarDelegate) {
var path = $location.path();
if (path.indexOf('submit') != -1)
$ionicNavBarDelegate.showBackButton(false);
else
$ionicNavBarDelegate.showBackButton(true);
})
You can also wrap hideBackButton value in object and your code will work:
.controller('AppCtrl', function($scope, $location) {
var path = $location.path();
$scope.options = $scope.options || {};
if (path.indexOf('submit') != -1)
$scope.options.hideBackButton = true;
else
$scope.options.hideBackButton = false;
})
It works because in JS (as in many other languages) booleans are passed by value and object are passed by the referance and it affects how default Angular watchers are created.
The downside of this method is that hidding of the button is not as smooth as in other ionic solutions.
Just in case, this is how your html should look like:
1st solution:
<body ng-app="starter" ng-controller="AppCtrl">
<ion-nav-bar class="bar-stable">
<ion-nav-back-button>
</ion-nav-back-button>
</ion-nav-bar>
</body>
2nd solution:
<body ng-app="starter" ng-controller="AppCtrl">
<ion-nav-bar class="bar-stable">
<ion-nav-back-button hide-back-button="{{options.hideBackButton}}">
</ion-nav-back-button>
</ion-nav-bar>
</body>
The hide-back-button attribute on <ion-view> did the trick for me: <ion-view hide-back-button="true">
See the official documentation here.
$ionicHistory.nextViewOptions({
disableBack: true
});
$state.go('app.home');
Ionic 2 & 3:
<ion-navbar [hideBackButton]="true">
A very simple way to achieve this is to apply the menu-close directive to your button/anchor. Technically it's meant for closing the menu, but you can use it on any link and it will bypass the slide animation & won't show the back button.
<a menu-close href="#/home">Home</a>
http://ionicframework.com/docs/api/directive/menuClose/
$ionicHistory.nextViewOptions({
disableBack: false,
historyRoot: true
});
That seems a good option to use, works fine for me.
You can change the cache settings so that when the page is reloaded the controller is called again:
http://ionicframework.com/docs/api/directive/ionNavView/
The hide-back-button attribute should be set on ion-view tag.
I had problems with "hide-back-button", since it hides the menu and the back button.
Somehow this.navCtrl.push played with the back button, in case you want the menu to be displayed using this.nav.setRoot(yourPage)

Resources