(function() { 'use strict'; angular.module('ionic.ui.viewState', ['ionic.service.view', 'ionic.service.gesture', 'ngSanitize']) /** * @ngdoc directive * @name ionView * @module ionic * @restrict E * @parent ionNavBar * * @description * A container for content, used to tell a parent {@link ionic.directive:ionNavBar} * about the current view. * * @usage * Below is an example where our page will load with a navbar containing "My Page" as the title. * * ```html * * * * * Hello! * * * * ``` * * @param {string=} title The title to display on the parent {@link ionic.directive:ionNavBar}. * @param {boolean=} hideBackButton Whether to hide the back button on the parent * {@link ionic.directive:ionNavBar}. * @param {boolean=} hideNavBar Whether to hide the parent {@link ionic.directive:ionNavBar}. */ .directive('ionView', ['$ionicViewService', '$rootScope', '$animate', function( $ionicViewService, $rootScope, $animate) { return { restrict: 'EA', priority: 1000, require: '^?ionNavBar', scope: { title: '@', hideBackButton: '&', hideNavBar: '&', }, compile: function(tElement, tAttrs, transclude) { tElement.addClass('pane'); tElement[0].removeAttribute('title'); return function link($scope, $element, $attr, navBarCtrl) { if (!navBarCtrl) { return; } navBarCtrl.changeTitle($scope.title, $scope.$parent.$navDirection); // Should we hide a back button when this tab is shown navBarCtrl.showBackButton(!$scope.hideBackButton()); // Should the nav bar be hidden for this view or not? navBarCtrl.showBar(!$scope.hideNavBar()); // watch for changes in the title $scope.$watch('title', function(val, oldVal) { //Don't send in initial value, changeTitle does that if (val !== oldVal) { navBarCtrl.setTitle(val); } }); }; } }; }]) /** * @ngdoc directive * @name ionNavView * @module ionic * @restrict E * @codepen HjnFx * * @description * As a user navigates throughout your app, Ionic is able to keep track of their * navigation history. By knowing their history, transitions between views * correctly slide either left or right, or no transition at all. An additional * benefit to Ionic's navigation system is its ability to manage multiple * histories. * * Ionic uses the AngularUI Router module so app interfaces can be organized * into various "states". Like Angular's core $route service, URLs can be used * to control the views. However, the AngularUI Router provides a more powerful * state manager in that states are bound to named, nested, and parallel views, * allowing more than one template to be rendered on the same page. * Additionally, each state is not required to be bound to a URL, and data can * be pushed to each state which allows much flexibility. * * The ionNavView directive is used to render templates in your application. Each template * is part of a state. States are usually mapped to a url, and are defined programatically * using angular-ui-router (see [their docs](https://github.com/angular-ui/ui-router/wiki)), * and remember to replace ui-view with ion-nav-view in examples). * * @usage * In this example, we will create a navigation view that contains our different states for the app. * * To do this, in our markup use the ionNavView top level directive, adding an * {@link ionic.directive:ionNavBar} directive which will render a header bar that updates as we * navigate through the navigation stack. * * ```html * * * * * * ``` * * Next, we need to setup our states that will be rendered. * * ```js * var app = angular.module('myApp', ['ionic']); * app.config(function($stateProvider) { * $stateProvider * .state('index', { * url: '/', * templateUrl: 'home.html' * }) * .state('music', { * url: '/music', * templateUrl: 'music.html' * }); * }); * ``` * Then on app start, $stateProvider will look at the url, see it matches the index state, * and then try to load home.html into the ``. * * Pages are loaded by the URLs given. One simple way to create templates in Angular is to put * them directly into your HTML file and use the ` * ``` * * This is good to do because the template will be cached for very fast loading, instead of * having to fetch them from the network. * * Please visit [AngularUI Router's docs](https://github.com/angular-ui/ui-router/wiki) for * more info. Below is a great video by the AngularUI Router guys that may help to explain * how it all works: * * * * @param {string=} name A view name. The name should be unique amongst the other views in the * same state. You can have views of the same name that live in different states. For more * information, see ui-router's [ui-view documentation](http://angular-ui.github.io/ui-router/site/#/api/ui.router.state.directive:ui-view). * @param {string=} animation The animation to use for views underneath this ionNavView. * Defaults to 'slide-left-right'. */ .directive('ionNavView', ['$ionicViewService', '$state', '$compile', '$controller', '$animate', function( $ionicViewService, $state, $compile, $controller, $animate) { // IONIC's fork of Angular UI Router, v0.2.7 // the navView handles registering views in the history, which animation to use, and which var viewIsUpdating = false; var directive = { restrict: 'E', terminal: true, priority: 2000, transclude: true, controller: ['$scope', function($scope) { this.setNextAnimation = function(anim) { $scope.$nextAnimation = anim; }; }], compile: function (element, attr, transclude) { return function(scope, element, attr, navViewCtrl) { var viewScope, viewLocals, name = attr[directive.name] || attr.name || '', onloadExp = attr.onload || '', initialView = transclude(scope); // Put back the compiled initial view element.append(initialView); // Find the details of the parent view directive (if any) and use it // to derive our own qualified view name, then hang our own details // off the DOM so child directives can find it. var parent = element.parent().inheritedData('$uiView'); if (name.indexOf('@') < 0) name = name + '@' + (parent ? parent.state.name : ''); var view = { name: name, state: null }; element.data('$uiView', view); var eventHook = function() { if (viewIsUpdating) return; viewIsUpdating = true; try { updateView(true); } catch (e) { viewIsUpdating = false; throw e; } viewIsUpdating = false; }; scope.$on('$stateChangeSuccess', eventHook); scope.$on('$viewContentLoading', eventHook); updateView(false); function updateView(doAnimate) { //===false because $animate.enabled() is a noop without angular-animate included if ($animate.enabled() === false) { doAnimate = false; } var locals = $state.$current && $state.$current.locals[name]; if (locals === viewLocals) return; // nothing to do var renderer = $ionicViewService.getRenderer(element, attr, scope); // Destroy previous view scope if (viewScope) { viewScope.$destroy(); viewScope = null; } if (!locals) { viewLocals = null; view.state = null; // Restore the initial view return element.append(initialView); } var newElement = angular.element('
').html(locals.$template).contents(); var viewRegisterData = renderer().register(newElement); // Remove existing content renderer(doAnimate).leave(); viewLocals = locals; view.state = locals.$$state; renderer(doAnimate).enter(newElement); var link = $compile(newElement); viewScope = scope.$new(); viewScope.$navDirection = viewRegisterData.navDirection; if (locals.$$controller) { locals.$scope = viewScope; var controller = $controller(locals.$$controller, locals); element.children().data('$ngControllerController', controller); } link(viewScope); var viewHistoryData = $ionicViewService._getViewById(viewRegisterData.viewId) || {}; viewScope.$broadcast('$viewContentLoaded', viewHistoryData); if (onloadExp) viewScope.$eval(onloadExp); newElement = null; } }; } }; return directive; }]); })();