I have an ionic app with some views, when I start the app I will go to my main view, when the controller of the view is initialized I will load some data.
The problem is, when I navigate from that view, using tabs, that controller is sometimes destroyed, so when I navigate back the data will have to load again.
I have done some testing with '$ionicView.loaded' and '$ionicView.unloaded' and it seems to be pretty random when the view is unloaded.
This is my state configuration
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('login', {
name: "login",
url: "/login",
templateUrl: "templates/login.html",
controller: 'loginCtrl'
})
// This is a sidemenu
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html'
})
.state('app.hms', {
url: '/hms',
views: {
'menuContent': {
templateUrl: 'templates/hms-app.html',
controller: 'HmsCtrl'
}
}
})
.state('app.hms-item', {
url: '/hms/:hmsId',
views: {
'menuContent': {
templateUrl: 'templates/hms-item.html',
controller: 'HmsItemCtrl'
}
},
params: {
item: null
}
})
.state('app.history', {
url: '/history',
views: {
'menuContent': {
templateUrl: 'templates/history-list.html',
controller: 'HistoryCtrl'
}
}
})
.state('app.history-item', {
url: '/history/:itemId',
views: {
'menuContent': {
templateUrl: 'templates/history-item.html',
controller: 'HistoryItemCtrl'
}
},
params: {
itemId: null
}
})
.state('app.event-new', {
url: '/event/new',
views: {
'menuContent': {
templateUrl: 'templates/event-new.html',
controller: 'EventCtrl as ctrl'
}
}
})
.state('app.risk-new', {
url: '/risk/new',
views: {
'menuContent': {
templateUrl: 'templates/risk-new.html',
controller: 'RiskCtrl as ctrl'
}
}
});
// if none of the above states are matched, use this as the fallback
// this is also the first page, 'front page'
$urlRouterProvider.otherwise('login');
});
My tabs are defined in each .html template I need them in (so not the login page, for instance), they are defined after the closing of ion-content:
<div class="tabs tabs-icon-top">
<a class="tab-item" href="#/app/hms">
<i class="icon ion-home"></i>
Home
</a>
<a class="tab-item" href="#/app/event/new">
<i class="icon ion-document-text"></i>
Hendelse
</a>
<a class="tab-item" href="#/app/risk/new">
<i class="icon ion-document-text"></i>
Risikorapport
</a>
<a class="tab-item" href="#/app/history">
<i class="icon ion-ios-list"></i>
Historikk
</a>
What could cause the controller of the view to be destroyed when I navigate from it?
Turns out, Ionic removes caching for views that are "forward", so when navigating back from a forward view that $scope will be destroyed.
This is explained under caching here
By default, when navigating back in the history, the “forward” views are removed from the cache. If you navigate forward to the same view again, it’ll create a new DOM element and controller instance. Basically, any forward views are reset each time. This can be configured using the $ionicConfigProvider:
So, configuring the $ionicConfigProvider with $ionicConfigProvider.views.forwardCache(true); fixed my issue
I also saw I could fix my issue another way, and that was to not make my views "forward", when navigating to a new view using href, we can specify what sort of view that should be, by doing nav-direction="swap", available directions are forward, back, enter, exit, and swap
Example of tab, with direction
<a class="tab-item" nav-direction="swap" nav-transition="android" href="#/app/home">
<i class="icon ion-home"></i>
Home
</a>
Related
I'm trying to create a nav bar with 3 links
I would like to get page.1 at the first time without clicking on page.1 ui-sref,
i have like html:
<nav>
<a ui-sref="page.1">Search</a>
<a ui-sref="page.2">Results</a>
<a ui-sref="page.3">Detail</a>
</nav>
<ui-view></ui-view>
My states are defined as follows:
angular.module('scrollDemo', ['ui.router'])
.config(function($stateProvider) {
$stateProvider
.state('page.1', {
url: '/page1',
templateUrl: '/Page1.html'
})
.state('page.2', {
url: '/page2',
templateUrl: '/Page2.html'
})
.state('page.3', {
url: '/page3',
templateUrl: '/Page3.html'
});
})
How can i procced ?
you can use $urlRouterProvider.otherwise('/path'); to set the detault path.
angular.module('scrollDemo', ['ui.router'])
.config(function($stateProvider,$urlRouterProvider) {
$urlRouterProvider.otherwise('/page.1');
$stateProvider
.state('page.1', {
url: '/page1',
templateUrl: '/Page1.html'
})
.state('page.2', {
url: '/page2',
templateUrl: '/Page2.html'
})
.state('page.3', {
url: '/page3',
templateUrl: '/Page3.html'
});
})
You seem like you want to immediately go to /page.1 when your application is loaded, what you can do is the following :
angular.module('scrollDemo', ['ui.router'])
.run(function($location) {
$location.path('/page1');
});
This will automatically change the path of your application to the desired one right after everything is loaded.
I have this classic ionic view refresh problem:
.state('app', {
url: '/app',
abstract: true,
templateUrl: 'templates/menu.html',
controller: 'AppCtrl'
})
.state('app.menu', {
url: "/menu",
views: {
'menuContent': {
templateUrl: "templates/headmenu.html"
}
}
})
.state('app.menu.media', {
url: "/media/:MediaType",
views: {
'media-tab': {
templateUrl: "templates/tabs/media.html",
controller: "MediaCtrl"
}
}
}).state('app.settings', {
url: "/settings",
views: {
'settingsContent': {
templateUrl: "templates/settings.html",
controller: "SettingsCtrl"
}
}
})
The app start from 'app.menu.media' state, I click on 'settings', the view is loaded, but the problem occurs when I try going back to 'app.menu.media' state, the view is not refreshed (I still have the 'settings' view)
One of the solutions suggested by other devs is using ui-sref-opts="{reload: true, notify: true}" inside a <a ui-sref="app.menu.media" ...> ..</a> tag, but it's not smooth, the users feel like if the app freezes for a short time, and the same goes for the javascript solution: $state.go('app.menu.media', {}, {reload: true});
I know that the controller is not loaded when it is in the same state, but in this example we have different controllers: "MediaCtrl" and "SettingsCtrl", so why we have this problem? Is there any clean solution to fix this problem?
Edit:
This problem occurs even if I'm disabling the cache: $ionicConfigProvider.views.maxCache(0);
After Debuging the app, I found that the problem was not related to cache, but it doesn't mean that enabling the views cache will not affect the app, disabling the cache was important for my case.
So the problem was related to the fact that I was using the same state "app" for both 'media' and 'settings' views, with different view names: "settingsContent" for "app.settings" and "menuContent" for "app.menu". So I had to add these two Ion-nav-views to the template Url linked to the "app" state, which is "menu.html", juste like this:
<ion-nav-view name="menuContent"></ion-nav-view>
<ion-nav-view name="settingsContent"></ion-nav-view>
So when I go back to "app.menu.media" state, the view is indeed loaded, but the "settings" view is still there, and it is hiding my new requested view "media"!
So what I did to fix this issue is to use the same Ion View name:
.state('app.menu', {
url: "/menu",
views: {
'THESAMENAME': {
templateUrl: "templates/headmenu.html"
}
}...
....
.state('app.settings', {
url: "/settings",
views: {
'THESAMENAME': {
templateUrl: "templates/settings.html",
controller: "SettingsCtrl"
}
}
And inside menu.html, I deleted the two previous lines, and replaced theme with:
<ion-nav-view name="THESAMENAME"></ion-nav-view>
I hope this could help someone
I'm try to use ui-router to manage nested views on a single page app.
Let's say I want to create a dashboard application with a common area and multiple views.
The main and the nested states are handled like this:
$stateProvider.state('home', {
url: '/',
template: 'MY HOME PAGE'
})
.state('login', {
url: '/login',
templateUrl: '/pages/login.html'
})
.state('registration', {
url: '/registration',
templateUrl: '/pages/registration.html'
})
.state('dashboard', {
url: '/dashboard',
templateUrl: '/pages/dashboard/dashboard.html'
})
.state('dashboard.me', {
url: '/me',
templateUrl: '/pages/dashboard/me.html'
})
.state('dashboard.messages', {
url: '/messages',
templateUrl: '/pages/dashboard/messages.html'
})
.state('dashboard.friends', {
url: '/friends',
templateUrl: '/pages/dashboard/friends.html'
});
The dashboard HTML page is the following:
<div class="container" ng-controller="dashboardCtrl" ng-init="init()">
<h2>DASHBOARD</h2>
<ul>
<li><a ui-sref="dashboard.me">Me</a></li>
<li><a ui-sref="dashboard.messages">My Messages</a></li>
<li><a ui-sref="dashboard.friends">My Friends</a></li>
</ul>
<div ui-view></div>
The above HTML is also included inside an ui-view.
Everything works fine if I navigate my application using the anchors.
By the way if I try to go directly to myhost/dashboard/me or myhost/dashboard/friends (every path with two levels of nested views) the app doesn't work. I get an angular (unexpected token <) but I don't think it's relevant...
It seems like it's not able to resolve the first level of nested view.
The following images show the HTML obtained when the navigation is done using anchors:
and the HTML obtained when the page is called directly from the browser address link:
Any ideas? Thanks.
The problem is that angular is not loading, hence the error. The code looks correct to me though, unless you missed the closing tag for
<div class="container" ng-controller="dashboardCtrl" ng-init="init()">
?
JavaScript State Configurations :
$stateProvider.state('home', {
url: '/',
template: 'MY HOME PAGE'
})
.state('login', {
url: '/login',
templateUrl: '/pages/login.html'
})
.state('registration', {
url: '/registration',
templateUrl: '/pages/registration.html'
})
.state('dashboard', {
url: '/dashboard',
abstract: true,
parent: 'home',
templateUrl: '/pages/dashboard/dashboard.html'
})
.state('dashboard.me', {
url: '/me',
views: {
'#dashboard_view': {
templateUrl: '/pages/dashboard/me.html'
}
}
})
.state('dashboard.messages', {
url: '/messages',
views: {
'#dashboard_view': {
templateUrl: '/pages/dashboard/messages.html'
}
}
})
.state('dashboard.friends', {
url: '/friends',
views: {
'#dashboard_view': {
templateUrl: '/pages/dashboard/friends.html'
}
}
});
Dashboard HTML
<div class="container" ng-controller="dashboardCtrl" ng-init="init()">
<h2>DASHBOARD</h2>
<ul>
<li><a ui-sref="dashboard.me">Me</a></li>
<li><a ui-sref="dashboard.messages">My Messages</a></li>
<li><a ui-sref="dashboard.friends">My Friends</a></li>
</ul>
<div ui-view="dashboard_view"></div>
You can get more details:
Multiple Named Views
Nested States and Nested Views
I am using angular pre-defined shell to build a basic working poc for my new project. Basic template is loaded by using ng-include in the index.html. But other views are linked to menu components using ui-router. Everything in the code side is perfect still I am having problem in loading the views when clicking on the menu items after running the shell.
I added the href tags to check if that works, but still no use.Could someone help me with this.
<li ng-class="{active: $state.includes('app')}">
<a href="">
<i class="fa fa-desktop"></i>
<span class="nav-label">{{ 'APPVIEWS' | translate }}</span>
<span class="pull-right label label-primary">SPECIAL</span>
</a>
<ul class="nav nav-second-level" ng-class="{in: $state.includes('app')}">
<li ui-sref-active="active">
<a ui-sref="app.contacts">Contacts</a>
</li>
</ul>
</li>
My states in config file are defined as :
function config($stateProvider, $urlRouterProvider, $ocLazyLoadProvider, IdleProvider, KeepaliveProvider) {
IdleProvider.idle(5);
IdleProvider.timeout(120);
$urlRouterProvider.otherwise("/dashboards/dashboard_1");
$ocLazyLoadProvider.config({
debug: false
});
$stateProvider
.state('app', {
abstract: true,
url: "/app",
templateUrl: "views/common/content.html",
})
.state('app.contacts', {
url: "/contacts",
templateUrl: "views/contacts.html",
data: { pageTitle: 'Contacts' }
})
}
If the "app" route is going to be abstract you can take the url off of it
the app.contacts could have a parent of the app route
$stateProvider
.state('app', {
"abstract": true,
templateUrl: "views/common/content.html",
})
So when i set up my "app" route as abstract and wanted all my other views to be nested inside of that route i defined a named view that they would go into
so my "app" template would be like
// html stuff here for app
<div ui-view="content"></div>
// more html stuff here
then my app.contacts route would look like
.state('app.contacts', {
parent: "app"
url: "/contacts",
views: {
"content": {
templateUrl: "views/contacts.html"
}
},
data: { pageTitle: 'Contacts' }
})
I have a UI-Router document set up to show the "pages" sections of a demo.
(function() {
'use strict';
angular.module('pb.ds.pages').config(function($stateProvider) {
$stateProvider.state('pages', {
abstract: true,
url: '/pages',
templateUrl: 'modules/pages/templates/pages.html',
controller: 'PagesController as pages',
data: {
pageTitle: 'Pages',
access: 'public',
bodyClass: 'pages'
}
})
.state('pages.signin', {
url: '/signin',
templateURL: 'modules/pages/templates/signin.html',
controller: 'SignInController as signin'
})
.state('pages.forgotpassword', {
url: '/forgotpassword',
templateURL: 'modules/pages/templates/forgotpassword.html',
controller: 'ForgotPasswordController as forgot'
})
.state('pages.404', {
url: '/404',
templateURL: 'modules/pages/templates/404.html',
controller: '404Controller'
});
});
})();
The parent state, "pages" has the ui-view on it, but otherwise I don't need to "show" it. I am only interested in showing its children, such as pages.signin or pages.forgotpassword.
Typing in the url "/forgotpassword" bounces me back to my homepage, which is the "otherwise" state in my app.module.js
// UI ROUTER CONFIG
angular.module('app').config(function($stateProvider) {
$stateProvider.state('otherwise', {
url: '*path',
template: '',
controller: function($state) {
$state.go('dashboard');
}
});
});
No errors in console, and all the pages in question are linked in my index.html.
I'm sure I must have missed something obvious. Any clues?
UPDATE
If I enter /pages/forgotpassword it does go to the correct path but the view is not being populated by the template...
There is a working plunker
We have to adjust state definition like this:
$stateProvider.state('pages', {
abstract: true,
//url: '/pages',
templateUrl: 'modules/pages/templates/pages.html',
controller: 'PagesController as pages',
data: {
pageTitle: 'Pages',
access: 'public',
bodyClass: 'pages'
}
})
.state('pages.signin', {
url: '/signin',
// templateURL: 'modules/pages/templates/signin.html',
templateUrl: 'modules/pages/templates/signin.html',
controller: 'SignInController as signin'
})
.state('pages.forgotpassword', {
url: '/forgotpassword',
//templateURL: 'modules/pages/templates/forgotpassword.html',
templateUrl: 'modules/pages/templates/forgotpassword.html',
controller: 'ForgotPasswordController as forgot'
})
The most important is replacement of the templateURL with templateUrl. Javascript (and UI-Router) is case sensitive.
We also do not need define url for parent... it could be just child state definition
Finally, we must be sure, that our parent contains some target ui-view="" where child states will be placed. E.g. this is the plunker pages.html:
<div>
<h3>pages</h3>
<hr />
<div ui-view=""></div>
</div>
These links will then work as expected:
//href
<a href="#/signin">
<a href="#/forgotpassword">
//ui-sref
<a ui-sref="pages.signin">
<a ui-sref="pages.forgotpassword">
We can leave the parent url:
$stateProvider.state('pages', {
abstract: true,
url: '/pages',
...
but the href links for child states must contain the parent url as well:
<a href="#/pages/signin">
<a href="#/pages/forgotpassword">
Check it here in action
You need to prefix the state url with the url of the parent state. So the correct url that you need open with the browser should be: #/pages/forgotpassword
Check the doc URL Routing for Nested States