I have a Ionic app based on the tabs template. The general navigation structure of my app is:
-- users (/users)
-- user (/users/[id])
-- todos (/todos)
-- todo (/users/[id])
-- settings (/settings)
There are some nested views there (user and todo). They appear in the same nav view, like so:
<ion-tabs class="tabs-icon-only tabs-color-assertive">
<ion-tab icon="ion-ios-pulse-strong" href="#/tab/users">
<ion-nav-view name="users-tab"></ion-nav-view>
</ion-tab>
<ion-tab icon="ion-ios-pulse-strong" href="#/tab/todos">
<ion-nav-view name="todos-tab"></ion-nav-view>
</ion-tab>
<ion-tab icon="ion-ios-pulse-strong" href="#/tab/settings">
<ion-nav-view name="settings-tab"></ion-nav-view>
</ion-tab>
</ion-tabs>
With states being defined thusly:
.state('tabs', {
url: '/tab',
abstract: true,
templateUrl: 'templates/tabs.html'
})
.state('users', {
url: '/users',
views: {
'users-tab': {
templateUrl: 'templates/tab-users.html',
controller: 'UsersCtrl'
}
}
})
.state('tabs.user', {
url: '/users/:userId',
views: {
'users-tab': {
templateUrl: 'templates/user-detail.html',
controller: 'UserCtrl'
}
}
})
.state('todos', {
url: '/todos',
views: {
'todos-tab': {
templateUrl: 'templates/tab-todos.html',
controller: 'TodosCtrl'
}
}
})
.state('tabs.todo', {
url: '/todos/:todoId',
views: {
'todos-tab': {
templateUrl: 'templates/todo-detail.html',
controller: 'TodoCtrl'
}
}
})
.state('tab.settings', {
url: '/settings',
views: {
'settings-tab': {
templateUrl: 'templates/tab-settings.html',
controller: 'SettingsCtrl'
}
}
})
In my index.html file, I have the following:
<ion-nav-bar class="bar-light">
<ion-nav-back-button></ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view></ion-nav-view>
I make use of the ion-nav-back-button to handle de master-detail views users and todos. This works completely automatically and Ionic handles this very well. Except for one case. When I refer to a detail view of a todo (e.g. /todos/3) from within another view (e.g. users/1), the back button does not appear, and there is no way to go back to the todos overview (/todos). A click on the tab button has no effect but going to /todos/3).
I guess this is expected behavior, but is there any way to show the back button anyway, or to make the tab button go to the todos view (/todos) at all times?
I found a solution. It's not ideal, but it works.
Instead of going directly to the detail state:
$state.go('tabs.todos', {
id: 1
});
I first go to the master state, and in the promise I go to the detail state:
$state.go('tabs.todos').then(function() {
setTimeout(function() {
$state.go('tabs.todos', {
id: 1
});
}, 100);
});
The timeout is not strictly necessary, but I've found that sometimes it fails without it.
I have my inside of my index.html I also have inject it in all the right places in app.js and this is my code for my badge:
<ion-tab title="Cart" icon-off="ion-ios-cart-outline" badge-style="badge-assertive" badge="{{tc.badgeNumber}}" icon-on="ion-ios-cart" href="#/tab/cart">
<ion-nav-view name="tab-cart"></ion-nav-view>
Then here's my code for my controller:
* Created by gabed on 3/3/16.
*/
(function(){
'use strict';
angular.module('tabModule', [])
.controller('tabCtrl', tabCtrl);
tabCtrl.$inject = ['cartService','$scope','$timeout'];
function tabCtrl(cartService,$scope,$timeout) {
var tc = this;
tc.badgeNumber = 5;
}
})();
You should be able to add the controller in your app.js file.
.state('tab', {
url: '/tab',
abstract: true,
controller: 'TabsCtrl',
templateUrl: "templates/tabs.html"
})
Whenever I try to add more than 3 modules to the angular dependencies I get this output:
Uncaught Error: [$injector:modulerr] Failed to instantiate module starter due to:
Error: [$injector:modulerr] Failed to instantiate module starter.vuelo due to:
Error: [$injector:nomod] Module 'starter.vuelo' is not available! You either misspelled the module name or forgot to load it. If registering a module ensure that you specify the dependencies as the second argument.
Any suggestions?
This is a factory.
I can not put more than one factory in a single module. And if I create a new module, I can not add it to dependencies because apparently there can not be more than 3.
For example:
angular.module('starter', ['ionic', 'starter.controllers','starter.services'])
This works but I need the other module
angular.module('starter', ['ionic', 'starter.controllers','starter.services','starter.vuelo'])
Breaks all navigation
services.js
angular.module('starter.services',['starter.controllers'])
.factory('MenuService', function() {
var menu = [
{
id:0,
titulo:'Buscar Charters',
descripcion:'',
icono:'ion-search'
},
{
id:1,
titulo:'Escalas vacias',
descripcion:'',
icono:'ion-plane'
},
{
id:2,
titulo:'Mi perfil',
descripcion:'',
icono:'ion-briefcase'
},
{
id:3,
titulo:'Mensajes',
descripcion:'',
icono:'ion-chatboxes'
}];
return {
all: function() {
return menu;
},
get: function(itemId) {
// Simple index lookup
return menu[itemId];
}
}
});
vuelo.js
angular.module('starter.vuelo',[])
.factory('VueloService', function () {
var vuelos = [{
id:1,
salida:{'MAN','Aeropuerto Augusto Cesar Sandino'},
destino:{'SJO','Juan Santamaria Intl'},
escalas:[],
aeronave:1,
asientos:4,
precioNormal:4199,
precioMiembro:2819,
horario:'diurno',
tiempoEstimado:45,
fechaVuelo:'20/10/14',
hora:'11:00am'
}];
return{
all: function() {
return vuelos;
},
get: function (vueloId) {
return vuelos[vueloId];
}
}
});
controllers.js
angular.module('starter.controllers', [])
.controller('MenuCtrl', function($scope, MenuService) {
$scope.menus = MenuService.all();
})
.controller('MenuDetalleCtrl', function($scope, $stateParams, MenuService) {
$scope.menu = MenuService.get($stateParams.menuId);
})
.controller('CharterCtrl', function($scope, $stateParams, VueloService) {
$scope.vuelos = VueloService.all();
});
app.js
angular.module('starter', ['ionic', 'starter.controllers','starter.services'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: '/tab',
abstract: true,
templateUrl: 'templates/tabs.html'
})
.state('tab.menu', {
url: '/menu',
views: {
'index-tab': {
templateUrl: 'templates/index-tab.html',
controller: 'MenuCtrl'
}
}
})
// .state('tab.opcion', {
// url: '/menu/:menuId',
// views: {
// 'index-tab': {
// templateUrl: 'templates/vuelosCharter.html',
// controller: 'MenuDetalleCtrl'
// }
// }
// })
.state('tab.charters', {
url: '/menu/0',
views: {
'index-tab': {
templateUrl: 'templates/buscarCharter.html',
controller: 'MenuDetalleCtrl'
}
}
})
.state('tab.escalas', {
url: '/menu/1',
views: {
'index-tab': {
templateUrl: 'templates/escalasVacias.html',
controller: 'CharterCtrl'
}
}
})
.state('tab.perfil', {
url: '/menu/2',
views: {
'index-tab': {
templateUrl: 'templates/datosCuenta.html',
controller: 'MenuDetalleCtrl'
}
}
})
.state('tab.mensajes', {
url: '/menu/3',
views: {
'index-tab': {
templateUrl: 'templates/buscarCharter.html',
controller: 'MenuDetalleCtrl'
}
}
})
.state('tab.cuenta', {
url: '/cuenta',
views: {
'cuenta-tab': {
templateUrl: 'templates/cuenta.html'
}
}
})
.state('tab.buscar', {
url: '/buscar',
views: {
'buscar-tab': {
templateUrl: 'templates/buscar.html'
}
}
});
// $urlRouterProvider
// .when('/menu/0',{
// templateUrl :'buscarCharter.html'
// })
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/tab/menu');
});
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<title>Jets</title>
<!-- ionic css -->
<link href="lib/css/ionic.css" rel="stylesheet">
<!-- your app's css -->
<link href="css/app.css" rel="stylesheet">
<!-- ionic/angularjs scripts -->
<script src="lib/js/ionic.bundle.js"></script>
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>
<!-- your app's script -->
<script src="js/app.js"></script>
<script src="js/services.js"></script>
<script src="js/controllers.js"></script>
<script src="js/vuelo.js"></script>
</head>
<!--
'starter' is the name of this angular module (js/app.js)
-->
<body ng-app="starter" animation="slide-left-right-ios7">
<!--
The nav bar that will be updated as we navigate between views
Additional attributes set its look, ion-nav-bar animation and icons
Icons provided by Ionicons: http://ionicons.com/
-->
<ion-nav-bar class="bar-positive">
<ion-nav-back-button class="button-icon button-clear ion-ios7-arrow-back">
</ion-nav-back-button>
</ion-nav-bar>
<!--
The views will be rendered in the <ion-nav-view> directive below
Templates are in the /templates folder (but you could also
have templates inline in this html file if you'd like).
-->
<ion-nav-view></ion-nav-view>
</body>
</html>
tabs.html
<ion-tabs class="tabs-icon-top tabs-default">
<ion-tab title="MenĂº" icon="icon ion-home" href="#/tab/menu">
<ion-nav-view name="index-tab"></ion-nav-view>
</ion-tab>
<ion-tab title="Mi cuenta" icon="icon ion-person" href="#/tab/cuenta">
<ion-nav-view name="cuenta-tab"></ion-nav-view>
</ion-tab>
<ion-tab title="Buscar" icon="icon ion-search" href="#/tab/buscar">
<ion-nav-view name="buscar-tab"></ion-nav-view>
</ion-tab>
</ion-tabs>
index-tab
<ion-view title="MenĂº">
<ion-content>
<ion-list>
<ion-item ng-repeat="menu in menus" type="item-text-wrap" href="#/tab/menu/{{menu.id}}" >
<i class="icon {{menu.icono}}"></i>
<p>{{menu.titulo}}</p>
</ion-item>
</ion-list>
</ion-content>
</ion-view>
escalasVacias.html
<ion-view title='Escalas vacias'>
<ion-content>
<ion-list>
<ion-item ng-repeat="vuelo in vuelos">
{{vuelo.id}}
</ion-item>
</ion-list>
</ion-content>
</ion-view>
Update:
I have tried what quicoli suggests, but it is not the case. I figured out that one object in the element was missing the keys, and throwed an Unexpected token exception.
salida:{'MAN','Aeropuerto Augusto Cesar Sandino'},
destino:{'SJO','Juan Santamaria Intl'},
salida:{'cod':'MAN','ap':'Aeropuerto Augusto Cesar Sandino'},
destino:{'cod':'SJO','ap':'Juan Santamaria Intl'},
Thanks
Friend,
I just got what's wrong... your vuelo.js has sintaxe erros.... below is the correct version:
angular.module('starter.vuelo',[])
.factory('VueloService', function () {
var vuelos = [{
id:1,
salida:{ id: 'MAN', name:'Aeropuerto Augusto Cesar Sandino'}, //<<--- here
destino:{id: 'SJO',name :'Juan Santamaria Intl'}, //<<--- and here
escalas:[],
aeronave:1,
asientos:4,
precioNormal:4199,
precioMiembro:2819,
horario:'diurno',
tiempoEstimado:45,
fechaVuelo:'20/10/14',
hora:'11:00am'
}];
return{
all: function() {
return vuelos;
},
get: function (vueloId) {
return vuelos[vueloId];
}
}
});
I'll give you a tip.... when you get a black screen when using angular/ionic, enter in chrome developer tools, I used that to see what was wrong.....
Now I now I could help you :)
your controller is dependent of 'starter.vuelo' module. See:
.controller('CharterCtrl', function($scope, $stateParams, VueloService) {
$scope.vuelos = VueloService.all();
});
So, when you declare you controller module, you should declare this dependency:
angular.module('starter.controllers', ['starter.vuelo'])
After doing that you can add back:
angular.module('starter', ['ionic', 'starter.controllers','starter.services','starter.vuelo'])
I hope I could help you. :)
Ideally, all 3 methods ought to work.
This codepen below shows all 3 methods well.
Correct and working CodePen Demo app
Currently, neither of the 3 methods work; the navbar just dissappears upon clicking the button (shows empty nav bar) while the core page remains the same main page.
Im not sure if its an code problem, ionic issue or just simply I should not transit to a new page from a navbar. The last one is too illogical to accept though.
Would any kind souls know where the issue lie and help me please?
My core content code in index.html
<body animation="slide-left-right-ios7">
<ion-nav-bar class="bar-light nav-title-slide-ios7"></ion-nav-bar>
<ion-nav-view></ion-nav-view>
The button html I have (Note all 3 versions were tested seperately)
<ion-view ng-controller="NavCtrl">
<ion-nav-buttons side="left">
<button class="button button-icon ion-compose" ng-click="create('tab.newpost')"></button>
<button class="button button-icon ion-compose" ui-sref="tab.newpost"></button>
<button class="button button-icon ion-compose" href="/tab/newpost"></button>
</ion-nav-buttons>
<ion-content class>
<!-- Rest of the content body here -->
</ion-content>
</ion-view>
Code in nav.js mainly for the state.create method
app.controller('NavCtrl', function ($scope, $location, $state, Post, Auth) {
$scope.post = {url: 'http://', title: ''};
$scope.create = function(stateName) {
/* $location.path('/tab/newpost'); */
$state.go(stateName); /* tried swapping stateName with 'tab.newpost' and func() */
};
});
Code for app.js (Route file)
var app = angular.module('MyApp', ['ionic','firebase']);
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('tab', {
url: '/tab',
abstract: true,
templateUrl: 'templates/tabs.html'
})
.state('tab.posts', {
url: '/posts',
views: {
'tab-posts': {
templateUrl: 'templates/tab-posts.html',
controller: 'PostsCtrl'
}
}
})
.state('tab.newpost', {
url: '/newpost',
views: {
'tab-newpost':{
templateUrl: 'templates/tab-newpost.html',
controller: 'NewCtrl'
}
}
});
/* + other states .... */
$urlRouterProvider.otherwise('/auth/login');
});
First method you used according to the your code look like this
ng-click="create('tab/newpost')"
It should be
ng-click="create('tab.newpost')"
i think you need to modify states name so you can navigate between them
var app = angular.module('MyApp', ['ionic','firebase']);
app.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('tab', {
url: '/tab',
abstract: true,
templateUrl: 'templates/tabs.html'
})
.state('tab.posts', {
url: '/posts',
views: {
'tab-posts': {
templateUrl: 'templates/tab-posts.html',
controller: 'PostsCtrl'
}
}
})
.state('tab.newpost', {
url: '/newpost',
views: {
'tab-posts':{ /* the same name of the above state */
templateUrl: 'templates/tab-newpost.html',
controller: 'NewCtrl'
}
}
});
/* + other states .... */
$urlRouterProvider.otherwise('/auth/login');
});
i'm new in ionic ( just a little less in angularjs ) .
i'm trying to do a simple switch between two views:
HTML
<body ng-app="starter" animation="slide-left-right-ios7">
<!--
The nav bar that will be updated as we navigate between views.
-->
<ion-nav-bar class="bar-stable nav-title-slide-ios7">
<ion-nav-back-button class="button-icon icon ion-ios7-arrow-back">
Back
</ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view name="intro"></ion-nav-view>
<ion-nav-view name="login"></ion-nav-view>
<ion-nav-view name="home"></ion-nav-view>
<ion-nav-view name="pizze"></ion-nav-view>
<ion-nav-view name="sponsor"></ion-nav-view>
<ion-nav-view name="scontrino"></ion-nav-view>
</body>
APP.js
.config(function($stateProvider, $urlRouterProvider) {
// Ionic uses AngularUI Router which uses the concept of states
// Learn more here: https://github.com/angular-ui/ui-router
// Set up the various states which the app can be in.
// Each state's controller can be found in controllers.js
$stateProvider
.state('intro', {
url: '/intro',
views: {
'intro': {
templateUrl: 'templates/intro.html',
controller: 'IntroCtrl'
}
}
})
.state('login', {
url: '/login',
views: {
'login': {
templateUrl: 'templates/login.html',
controller: 'LoginCtrl'
}
}
})
$urlRouterProvider.otherwise('/intro');
});
Controllers.js
angular.module('starter.controllers', [])
.controller('IntroCtrl', function($scope,$location) {
$location.url("/login");
})
.controller('LoginCtrl', function($scope,$location) {
})
Intro is shown correctly but when it tries to change location to "login.html" it says:
TypeError: Cannot read property 'querySelectorAll' of undefined
at cancelChildAnimations (http://localhost:8000/www/lib/ionic/js/ionic.bundle.js:30611:21)
at Object.leave (http://localhost:8000/www/lib/ionic/js/ionic.bundle.js:30176:11)
at Object.leave (http://localhost:8000/www/lib/ionic/js/ionic.bundle.js:38411:24)
at updateView (http://localhost:8000/www/lib/ionic/js/ionic.bundle.js:41540:31)
at eventHook (http://localhost:8000/www/lib/ionic/js/ionic.bundle.js:41501:17)
at Scope.$broadcast (http://localhost:8000/www/lib/ionic/js/ionic.bundle.js:21190:28)
at $state.transition.resolved.then.$state.transition (http://localhost:8000/www/lib/ionic/js/ionic.bundle.js:33975:22)
at wrappedCallback (http://localhost:8000/www/lib/ionic/js/ionic.bundle.js:19894:81)
at http://localhost:8000/www/lib/ionic/js/ionic.bundle.js:19980:26
at Scope.$eval (http://localhost:8000/www/lib/ionic/js/ionic.bundle.js:20906:28)
What could be the problem???
Thanks!
Try this
angular.module('starter.controllers', [])
.controller('IntroCtrl', function($scope,$state) {
$state.transitionTo("login");
})
.controller('LoginCtrl', function($scope,$location) {
})
You are using the view names wrong.
In a state, the view's name
views: {
'_name_': {
}
is used for different navigation histories for different views.
Say you have two tabs, home and pizza, and you want both to have several pages, then the view name comes in handy.
For your example it is important to know, how you want the views to be used.
I set up an example for you, making the views accessible in tabs.
See here for that example: http://plnkr.co/edit/Yd5ehQd0wnwlPzP0KYnp?p=preview