Angularjs template view is not being cached, it refreshes every time - angularjs

Scratching my head on this one, I have a tab that has two views in it, the default view and a secondary view. The user must click a button (in the default view) to get to the secondary view...and once in the secondary view must click a button to go back to the default view.
I have cache: true, on both views and caching is working (as intended) on the default view, but is not working on the secondary view. Every time the user goes to the secondary view it refreshes the content with a call to the server. Regardless of which view the user is on, if the user goes to another tab and comes back again, neither default or secondary views get refreshed (as intended), its only when switching from the default view to the secondary view does it happen.
There is nothing else in the controllers for either views that is messing with or dealing with cache. How can I resolve this or what can I look for that might be causing this?
In app.js:
.state('tab.current', { // primary/default view
cache: true,
url: '/current',
params: tabParams,
views: {
'tab-current': {
templateUrl: 'templates/tab-current.html',
controller: 'CurrentCtrl'
}
}
})
.state('tab.current-detail', {
cache: true,
url: '/current/:ceID',
params: tabParams,
views: {
'tab-current': {
templateUrl: 'templates/detail-current.html',
controller: 'CurrentDetailCtrl'
}
}
})
.state('tab.past', { // secondary view
cache: true,
url: '/past',
params: tabParams,
views: {
'tab-current': {
templateUrl: 'templates/tab-past.html',
controller: 'PastCtrl'
}
}
})
.state('tab.past-detail', {
cache: true,
url: '/past/:ceID',
params: tabParams,
views: {
'tab-current': {
templateUrl: 'templates/detail-past.html',
controller: 'PastDetailCtrl'
}
}
})
I am using Ionic tabs:
<ion-tabs id="allTabs" delegate-handle="mainTabs" class="tabs-icon-bottom tabs-bottom tabs-color-active-positive" style="">
<div id="allTabsBar" style="height:100%;">
<!-- Home Tab -->
<ion-tab id="homeTab" class="icon barIconHeight" icon-off="ion-home" icon-on="ion-home" href="#/tab/home" >
<ion-nav-view id="tab-home" name="tab-home"></ion-nav-view>
</ion-tab>
<!-- Club Tab -->
<ion-tab id="clubTab" class="icon barIconHeight" icon-off="ion-people" icon-on="ion-people" href="#/tab/clubs" >
<ion-nav-view id="tab-clubs" name="tab-clubs"></ion-nav-view>
</ion-tab>
<!-- Search Tab -->
<ion-tab id="searchTab" class="icon barIconHeight" icon-off="ion-search" icon-on="ion-search" href="#/tab/search" >
<ion-nav-view id="tab-search" name="tab-search"></ion-nav-view>
</ion-tab>
<!-- Settings Tab -->
<ion-tab id="menuTab" class="icon barIconHeight" icon-off="ion-ios-settings-strong" icon-on="ion-ios-settings-strong" href="#/tab/menu" >
<ion-nav-view id="tab-menu" name="tab-menu"></ion-nav-view> <!-- class="icon ion-ios-settings-strong" -->
</ion-tab>
</div>
</ion-tabs

I believe your issue is likely your usage of href. AngularJS probably isn't getting a chance to pass off your hash routing to the location service. Since the template cache is not backed by any persistence layer (local/session storage), a full page reload will clear any cached templates.
See ngHref

Related

Controller executing twice with ui-router nested states (Ionic)

Problem
My Ionic app lets you choose a Project from the side menu, and then displays two tabs (Tasks, Messages) in the main content area. The tasks and messages tabs are nested states of project.
When you change projects in the side menu, TaskListCtrl gets executed twice. See the live demo and watch the console as you change between projects. I also have a video which shows the issue in detail.
How do I stop TaskListCtrl from executing twice? Is there a better way I could be structuring these nested states?
Code
Full code is on GitHub »
Here's my $stateProvider config:
.state('project', {
url: "/projects/:projectID",
abstract: true,
cache: false,
controller: 'ProjectDetailCtrl',
templateUrl: "templates/project.tabs.html",
resolve: {
project: function($stateParams, Projects) {
return Projects.get($stateParams.projectID);
}
}
})
.state('project.tasks', {
url: '/tasks',
views: {
'tasks-tab': {
templateUrl: 'templates/task.list.html',
controller: 'TaskListCtrl'
}
}
})
And the relevant snippet from controllers.js:
.controller('ProjectDetailCtrl', function($scope, project) {
$scope.project = project;
console.log('=> ProjectDetailCtrl (' + $scope.project.name + ')')
})
.controller('TaskListCtrl', function($scope, $stateParams) {
$scope.tasks = $scope.project.tasks;
console.log('\t=> TaskListCtrl')
console.log('\t\t=> $stateParams: ', $stateParams)
console.log('\t\t=> $scope.tasks[0].title: ', $scope.tasks[0].title)
})
Resources
Live demo (watch the console logs as you change between projects)
Video showing the issue
Code on GitHub
Notes
I am aware there are similar questions on StackOverflow — however, none of the solutions they offer solved my issue.*
I've read this can happen when attaching the controller both in $stateProvider and with ng-controller — however, I've checked and I'm not doing this. I'm only attaching the controller with $stateProvider.
I guess tuckerjt07 is right.
It seems to be an issue with routing and parameters and ionic tabs.
I've spend almost the whole day trying to figure out what is going on.
I thought the problem was with the fact you're using an abstract controller with parameters, but that's not the problem.
I've checked if the side menu was interfering with tabs but, again, the problem is not there.
I've checked the scope trying to eliminate friction using controllerAs and avoiding to reference the $scope object to store the viewmodel but ... nothing.
I've created a simplified version of your application here.
There's not much in there and the navigation is through constants in the header.
As you can see the problem is still there.
Doing a little bit of debugging it seems that the problem sits here.
That line calls the controller twice. You can check it yourself adding a breakpoint at line 48435 in ionic.bundle.js.
The only option you have is to change your project.tabs.html and load the list of tasks without the sub-view. Something like this:
<ion-view view-title="{{ project.name }}: Tasks">
<ion-tabs class="tabs-icon-top tabs-positive">
<ion-tab title="{{ project.name }} Tasks" icon="ion-home">
<ion-nav-view>
<ion-content>
<ion-list>
<ion-item class="item-icon-right" ng-repeat='task in project.tasks'>
{{ task.title }}
<i class="icon ion-chevron-right icon-accessory"></i>
</ion-item>
</ion-list>
</ion-content>
</ion-nav-view>
</ion-tab>
<ion-tab title="About" icon="ion-ios-football" ui-sref="tabs.tab2">
<ion-nav-view name="tabs-tab2"></ion-nav-view>
</ion-tab>
<ion-tab title="Another" icon="ion-help-buoy" ui-sref="tabs.tab3">
<ion-nav-view name="tabs-tab3"></ion-nav-view>
</ion-tab>
</ion-tabs>
</ion-view>
You can check how it works here.
I guess we should open an issue.

Ionic Framework Page Transition

Does anyone successfully add a page transition on nested views in angularjs/ionicframework
This is my code for my nested views. When I go to this page transition is not working
<ion-side-menus>
<ion-nav-view name="left"></ion-nav-view>
<ion-nav-view name="main"></ion-nav-view>
</ion-side-menus>
But if I put only this code
<ion-nav-view name="main"></ion-nav-view>
Page transition is working
I hope you can help me with this one. Thank you!
In you index.html you should have a single ion-nav-view (you can populate this ion nav view with multiple ion views) like so:
<div ng-app="ffApp" animation="slide-left-right" ng-controller="authRoute.controller">
<ion-nav-view></ion-nav-view>
Then you want to create states/child states to fill the view:
$stateProvider
.state('authenticate', {
url: '/authenticate',
templateUrl: 'templates/authentication.html'
})
.state('loginIos', {
url: '/loginIos',
templateUrl: 'templates/loginIos.html',
controller: 'loginIos.controller',
})
.state('home', {
url: '/home',
templateUrl: 'templates/home.html',
controller: 'home.controller',
}).state('home.home1', {
url: "/home",
views: {
'menuContent' :{
templateUrl: "home.html"
}
}
})
Inside the template file you will have a ion-view with a side menu, if you want to populate the side menu as a child state you can create a child state inside the state provider and then place a ion-nav-view in side menu.
<ion-view>
<ion-side-menus>
<!-- Center content -->
<ion-side-menu-content ng-controller="ContentController">
<!-- Left menu -->
<ion-side-menu side="left">
</ion-side-menu>
<!-- Right menu -->
<ion-side-menu side="right">
</ion-side-menu>
<ion-side-menu-content>
<!-- Main content, usually <ion-nav-view> -->
</ion-side-menu-content>
</ion-side-menus>
</ion-view>
then when you navigate to a child state such as home.home1 the template for home.home1 will fill the menucontent ion-nav-view which is included in the home state template.
See this example: http://codepen.io/mhartington/pen/Bicmo/

ionic $state.go redirect does not load ui correctly until click

I am using ionic with firebase, and am trying to redirect upon login to the home page. The $state.go redirect does work, however I have a hidden tab called 'Profile', that I do not show until the user is authenticated. This tab remains hidden on the $state.go redirect, and doesn't show until I click on the 'Home' tab again. How do you load the load the ui on a redirect?
HTML:
tabs HTML:
<ion-tabs class="tabs-icon-top tabs-color-active-positive" ng-controller="LoginCtrl">
<!-- Login Tab -->
<ion-tab title="Login" icon-off="ion-locked" icon-on="ion-locked" href="#/tab/login">
<ion-nav-view name="tab-login"></ion-nav-view>
</ion-tab>
<!-- Dashboard Tab -->
<ion-tab title="New Post" icon-off="ion-compose" icon-on="ion-compose" href="#/tab/new">
<ion-nav-view name="tab-new"></ion-nav-view>
</ion-tab>
<!-- Chats Tab -->
<ion-tab title="Home" icon-off="ion-ios-home" icon-on="ion-ios-home" href="#/tab/home">
<ion-nav-view name="tab-home"></ion-nav-view>
</ion-tab>
<!-- Account Tab -->
<ion-tab class="{{hiddenProfileTab()}}" title="Profile" icon-off="ion-person" icon-on="ion-person" href="#/tab/profile">
<ion-nav-view name="tab-profile"></ion-nav-view>
</ion-tab>
</ion-tabs>
Login Controller
.controller('LoginCtrl', ['$scope', '$rootScope', '$state', '$location', function($scope, $rootScope, $state, $location) {
$scope.hiddenProfileTab = function(){
// return "ng-hide";
if ($rootScope.currentUser){
return "ng-show";
} else {
return "ng-hide";
}
}
//DO SOME THINGS
// $location.path('tab.home')
// $state.go('tab.home')
// $state.go('tab.home'), {}, { reload: true }
$state.go('tab.home',{},{location:'replace'});
};
}])
To reiterate the problem, the Profile tab remains hidden on the $state.go redirect to the 'home' page, until the 'home' page tab is clicked.
Any ideas how to load the UI on the redirect?
Use ng-show instead of using class attribute with {{}} interpolation.
<ion-tab ng-show="currentUser" title="Profile" icon-off="ion-person" icon-on="ion-person" href="#/tab/profile">
<ion-nav-view name="tab-profile"></ion-nav-view>
</ion-tab>
Solved this by setting the cache:false so that the controller is forced to load again.
.state('tab.home', {
cache: false,
url: '/home',
views: {
'tab-home': {
templateUrl: 'templates/tab-home.html',
controller: 'HomeCtrl'
}
}
})
Not sure if it is directly attributable to this specific problem, but when I encountered a similar issue with elements not displaying until the user started interacting with the UI, I found that the issue was due to having multiple elements with the same "id" attribute value.
In my case it was related to a loader animation icon that I was using on multiple views. I always had the loader id set to the same thing ("loading-progress"). When showing and hiding my loader I was experiencing weird behaviors until I made sure to name each loader uniquely.
Ultimately, I think my problem was due to not treating angular as being a single page app but coding as though it were a full site with unique pages and views. It's easy to just concentrate on the view at hand and forget that it's actually sitting in a big set of nested views and html snippets.
Edit: Also, I should have mentioned, another common issue where content does not appear (especially dynamically loaded content) often relates to window/div resizing. In particular, if you begin with a hidden div that you then populate with data through an api call, you often need to conclude it with a call to:
$ionicScrollDelegate.resize()
to force the size of the div to be recalculated. Without this, your data can be loaded but still not visible because the parent div is still hanging out with a 0px height.
Edit again!:
Also, when working with ng-repeat and similar dynamic angular databinding, to force the ng logic to re-sync the html with the data you can use:
$scope.$apply();

Navigation with tabs not working

I am trying to do navigation to tab list after selecting some items from the list.
when I am trying to run my code I am getting Cannot GET /tab/1337
my selection from the list looks like:
<div class="list">
<a ng-repeat="item in items"
href="/tab/{{item.queId}}"
class="item item-thumbnail-left">
My app.js looks like
.state('tabs.details', {
url: "/details/:itemqueId",
views: {
'details-tab': {
templateUrl: "templates/details.html",
controller: 'FriendDetailCtrl'
}
}
})
.state('tabs', {
url: "/tab/:itemqueId",
abstract: true,
templateUrl: "templates/tabs.html"
});
my tabs.html looks like:
<ion-view>
<ion-tabs class="tabs-icon-top">
<!-- Pets Tab -->
<ion-tab title="Dashboard" icon="icon ion-home" href="#/tab/dash">
<ion-nav-view name="tab-dash"></ion-nav-view>
</ion-tab>
<!-- Adopt Tab -->
<ion-tab title="details" icon="icon ion-heart" href="#/tab/details">
<ion-nav-view name="tab-details"></ion-nav-view>
</ion-tab>
</ion-tabs>
</ion-view>
don't know what can be the issue, but hope you will help!
Thanks!
Remove the line saying abstract: true in the tabs state definition - abstract states can not get activated. See ui-router docs.
Update:
What do you actually expect to happen when hitting /tab/1337?
Available Tabs
First of all, taking a look at the current state config, you have only a single valid route, since the tab state is abstract:
/tab/:itemqueId/details/:itemqueId
See how tab.details it will append it's url the one of tab, since it's a nested state of tabs. Therefor /tab/1337 is not a valid route.
What you might be looking for is /tab/:itemqueId/details - therefor change your url for tab.details to url: "/details"
Linking
Instead of using the href attribute, you should always prefer using the ng-href directive when interpolating variables from the angular scope.
In this case I'd even suggest to use ui-sref directive from ui-router. This way you can create urls with state definition and also check if your definition is valid.
<a ui-sref="tab.details({ itemqueId: item.queId })">
In the tabs.html your links should look like this to point to an sibling state - given that tabs.dash is a valid state similar to tabs.details:
<!-- Pets Tab -->
<ion-tab title="Dashboard" icon="icon ion-home" ui-sref="^.dash">
<ion-nav-view name="tab-dash"></ion-nav-view>
</ion-tab>
<!-- Adopt Tab -->
<ion-tab title="details" icon="icon ion-heart" href="^.details">
<ion-nav-view name="tab-details"></ion-nav-view>
</ion-tab>

Angularjs + Ionic Framework: How to create a new route that shows the ion-tabs navigation but without defining a tab for itself?

Long title but here is a better explanation.
I have a template html file called "Login". I define a route in app.js like so
.state('login', {
url: '/login',
templateUrl: 'templates/login.html',
controller: 'createAccountCtrl'
})
By using ui-sref="login" I can link to this template from anywhere which is perfect for my needs.
However the main app uses an abstract route "tab" to load the tabs template which contains the main navigation.
.state('tab.about', {
url: '/about',
views: {
'about-tab': {
templateUrl: 'templates/about.html',
controller: 'aboutCtrl'
}
}
})
<ion-tabs tabs-style="tabs-icon-top" tabs-type="tabs-default">
<!-- Home Tab -->
<ion-tab title="Home" icon="icon ion-home" href="#/tab/home">
<ion-nav-view name="home-tab"></ion-nav-view>
</ion-tab>
<!-- Products Tab -->
<ion-tab title="Earn Points" icon="icon ion-ios7-plus-outline" href="#/tab/retail-store">
<ion-nav-view name="retail-store-tab"></ion-nav-view>
</ion-tab>
</ion-tabs>
My problem is this. I want the Login page to have the main app's navigation like every other page has. That way a user who makes it to the login page, if they don't to login can still navigate off to the home or about page. But, I do not want a navigation tab/icon of its own to show.
Is is possible to just add the tabs html directly to the login.html template file or possibly hide the login icon/tab. I am open to suggestions and help. Thank you!
The tabs are meant to have their own tab icon. So you can't put the login page inside the tabs abstract view without creating a tab icon for it.
Instead of putting the login page under the tab abstract view, you should just put a separate tabbed navigation for the login page.
Load the following view into your index page.
<ion-view title="'Login'">
<ion-content has-header="true" has-footer="true" padding="true">
Login page content goes here
</ion-content>
<div class="tabs tabs-icon-left">
<a class="tab-item" href="#/tab/home">
Home
</a>
<a class="tab-item" href="#/tab/about">
About
</a>
</div>
</ion-view>

Resources