How to keep the content of a ui-view between different states? - angularjs

My application has 3 'ui-views':
nav#
main#
side#
my states whitin the router are like this:
.state('home', {
url: "/home",
views: {
'nav#': { templateUrl: "views/navigation/main.html" },
'main#': { templateUrl: "views/home/main.html" },
'side#': { templateUrl: "views/home/side.html" }
}
})
this one works fine, all three views are rendered.
.state('home.detail', {
url: "/{id}",
views: {
'side#': { templateUrl: "views/home/side.html" }
}
})
This one works also, only the 'side#' view is updated.
Now for the third route, I want to keep the "nav#" view in the same state, like it is done in the "home.detail" route for the 'main#' and 'nav#' views.
.state('seminar', {
url: "/seminar/{id}",
views: {
'main#': { templateUrl: "views/seminars/main.html" },
'side#': { templateUrl: "views/seminars/side.html" }
}
})
Unfortunately, the 'nav#' view is rendered blank when opening the route. Is there a way to tell angular to not clear the view and keep the content?
I could declare the 'nav#' template, but I was wondering if there is a way around this.

Related

$state.go() clears $historyStack in ionic

In Ionic I got a slider in one tab. On click on a slide I want to jump to a subpage on another tab. I achieve that using
$state.go('^.station', {stationId:clickedSlide});
I get to view alright, but there is no back button to the root view (.stationen) of this tab. It seems to clear the entire historyStack of this tab. Even if I try to first jump to .stationen first and then to .station I do not get a back button.
My stateProvider looks like so:
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: '/tab',
abstract: true,
templateUrl: 'templates/tabs.html'
})
// Each tab has its own nav history stack:
.state('tab.map', {
url: '/map',
views: {
'tab-map': {
templateUrl: 'templates/tab-map.html',
controller: 'MapController'
}
}
})
.state('tab.stationen', {
url: '/stationen',
views: {
'tab-stationen': {
templateUrl: 'templates/tab-stationen.html',
controller: 'StationenCtrl'
}
}
})
.state('tab.station', {
url: '/stationen/:stationId',
views: {
'tab-stationen': {
templateUrl: 'templates/tab-station.html',
controller: 'ChatDetailCtrl'
}
}
})
.state('tab.account', {
url: '/account',
views: {
'tab-account': {
templateUrl: 'templates/tab-account.html',
controller: 'AccountCtrl'
}
}
});
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/tab/map');
});
I tried setting options in my $state.go() call but to no avail. Also nesting the .station in .stationen did not get me any results. What am I missing?

UI router - Multiple nested named views in a single state

index.html
--navbar.html
--content.html
--customer.html
--netScore.html
--useExp.html
--useExpNest1.html
--useExpNest2.html
--internalPerformance.html
--leftNavPanel.html
I have this kind of view structure and I want to load them all at once so I'm planning to put this in a single state. I saw this answer but it seems that its only applicable for a simple/double nested views(I have 3 or more nested views). How can I put this in a single state, or is there a better way if not possible?
EDIT
I've come up with this solution and it works somehow.
.state('index', {
url: '/',
views: {
'': {
templateUrl: 'app/modules/bulletin/views/index.view.html',
controller: 'indexController'
},
'navbar#index': {
templateUrl: 'app/modules/bulletin/views/index/navbar.view.html',
controller: 'navbarController'
},
'content#index': {
templateUrl: 'app/modules/bulletin/views/index/content.view.html',
controller: 'contentController'
},
'leftNavPanel#index': {
templateUrl: 'app/modules/bulletin/views/index/leftNavPanel.view.html',
controller: 'contentController'
}
}
})
.state('index.content', {
views: {
'customer#index': {
templateUrl: 'app/modules/bulletin/views/index/content/customer.view.html'
},
'internalPerformance#index': {
templateUrl: 'app/modules/bulletin/views/index/content/internalPerformance.view.html'
}
}
})
.state('index.content.customer', {
views: {
'netScore#index.content': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/netScore.view.html'
},
'useExp#index.content': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/useExp.view.html'
}
}
})
.state('index.content.customer.useExp', {
views: {
'useExpNest1#index.content.customer': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/useExp/useExpNest1.view.html'
},
'useExpNest2#index.content.customer': {
templateUrl: 'app/modules/bulletin/views/index/content/customer/useExp/useExpNest2.view.html'
}
}
})
And then add this code to the indexController(most parent controller)
$state.go('index.content');
$state.go('index.content.customer');
$state.go('index.content.customer.useExp');
But this answer is still wrong because, let's say that netScore.html has some child views, we will create route for it then go to that state, but netScore and useExp states are on the same level so only one of them will be loaded if we use
$state.go('index.content');
$state.go('index.content.customer');
$state.go('index.content.customer.netScore');
$state.go('index.content.customer.useExp');
EDIT 2
Here's a plunker of what I've done so far. The view names are slightly different but you will see clearly the problem there
You can use a combination of named views plus abstract: true property to load child views by default
angular.module('sampleModule', [
'ui.router'
]);
angular.module('sampleModule')
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.when('','/');
$stateProvider
.state('main', {
url: '',
abstract: true,
templateUrl: 'main.view.html'
})
.state('main.load', {
url: '/',
abstract: true,
views:{
'content':{
templateUrl:'content.view.html',
},
'navbar':{
templateUrl:'navbar.view.html',
}
}
})
.state('main.load.customer', {
url: '',
abstract: true,
views:{
'customerPerception':{
templateUrl:'content-customerPerception.view.html'
},
'customerExperience':{
templateUrl:'content-customerExperience.view.html'
}
}
})
.state('main.load.customer.netTrustScore', {
url: '',
abstract: true,
views: {
'netTrustScore': {
templateUrl: 'content-customerPerception-netTrustScore.view.html'
},
'useExperience': {
templateUrl: 'content-customerPerception-useExperience.view.html'
},
'trustStatements': {
templateUrl: 'content-customerPerception-trustStatements.view.html'
}
}
})
.state('main.load.customer.netTrustScore.somethingElse', {
url: '',
views: {
'abc': {
templateUrl: 'content-customerExperience-customerComplaints.view.html'
},
'': {
templateUrl: 'content-customerExperience-networkQualityIndex.view.html'
}
}
})
;
}])
.controller('mainController', ['$scope', '$state', function($scope, $state) {
console.log('mainController initialized!');
}]);
here's a plnkr
https://plnkr.co/edit/BBAeWjnGbTsbO1lMguU9?p=preview
Thanks to the guys from AngularJS group in FB. The problem is I put two sibling views in two different states. UI router cant load two states at the same time. So the solution is to put all same level views in a single subState.
Lets assume we have this kind of structure:
index.html
--navbar.html
--content.html
--customer.html
--netScore.html
--netScoreNest1.html
--netScoreNest2.html
--useExp.html
--useExpNest1.html
--useExpNest2.html
--internalPerformance.html
--leftNavPanel.html
the proper routing for this would be like this
.state('index', {
url: '/',
views: {
'': {
templateUrl: 'index.view.html',
controller: 'mainController'
},
'navbar#main': {
templateUrl: 'index/navbar.view.html'
},
'content#main': {
templateUrl: 'index/content.view.html'
},
'leftNavPanel#main': {
templateUrl: 'index/leftNavPanel.view.html'
}
}
})
.state('index.subLevel', {
views: {
'customer#index': {
templateUrl: 'index/content/customer.view.html'
},
'internalPerformance#index': {
templateUrl: 'index/content/internalPerformance.view.html'
}
// IF LEFTNAVPANEL OR NAVBAR HAVE SUB VIEWS, PUT IT HERE
}
})
.state('index.subLevel.subLevel2', {
views: {
'netScore#index.subLevel': {
templateUrl: 'index/content/customer/netScore.view.html'
},
'useExp#index.subLevel': {
templateUrl: 'index/content/customer/useExp.view.html'
}
// IF INTERNALPERFORMANCE HAVE SUB VIEWS, PUT IT HERE
}
})
.state('index.subLevel.subLevel2.subLevel3', {
views: {
'netScoreNest1#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/netScore/netScoreNest1.view.html'
},
'netScoreNest2#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/netScore/netScoreNest2.view.html'
},
'useExpNest1#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/useExp/useExpNest1.view.html'
},
'useExpNest2#index.subLevel.subLevel2': {
templateUrl: 'index/content/customer/useExp/useExpNest2.view.html'
}
}
})
And then in mainController, load the inner most child state, this will automatically load the views of all its parent(up to topmost parent state 'index')
$state.go('index.subLevel.subLevel2.subLevel3');
And thats it. And also here's a plunker to make it easier to understand. (Views and structure are slightly different from this post different. Too lazy to edit)

UI-Router nested - multiple views , hold a view and change another view the same time

Consider the layout below:
I've got two views, view A and view B. I'm trying to load user menu in A view and menu contents in B view.
I tried this:
First I loaded my menu in A view, then when I tried to view a menu , ui-router will make A view empty and load B view.
How could I hold A view state while B view state is changing?
Perhaps the way I'm doing this is totally wrong.
Update 1:
Here is my route config:
$stateProvider
.state("login", {
url: "/login",
views: {
"login": {
templateUrl: "./static/views/login.html",
controller: loginController
}
}
})
.state("dashboard", {
url: "/dashboard",
views: {
"view-a": {
templateUrl: "./static/views/dashboard.html"
}
}
})
.state("test", {
url: "/test",
views: {
"view-b": {
templateUrl: "./static/views/test.html"
}
}
});
It seems you want B to be a nested view of A. There a few differernt ways to achieve this, here are the docs https://github.com/angular-ui/ui-router/wiki/Nested-States-and-Nested-Views
This approach will give a possible route to view B at /dashboard/test
$stateProvider
.state("login", {
url: "/login",
views: {
"login": {
templateUrl: "./static/views/login.html",
controller: loginController
}
}
})
.state("dashboard", {
url: "/dashboard",
views: {
"view-a": {
templateUrl: "./static/views/dashboard.html"
}
}
})
.state("dashboard.test", {
url: "/test",
views: {
"view-b": {
templateUrl: "./static/views/test.html"
}
}
});
Inside dashboard.html you can reference view-b by having <div ui-view="view-b"></div>

AngularJS. Default child state with named views

I am using UI Router for my application. Their FAQ page covers default child state question, but they are not using named views and i can't figure out how to get this working.
Here are samples of my code:
index.html
<a ui-sref="/">Home</a>
<a ui-sref="topic.basics">Basics</a>
<a ui-sref="topic.payments">Payments</a>
<div ui-view="container" class="container"></div>
app.js
$stateProvider
.state("/", {
url: "/"
})
.state("topic", {
url: "/topic/",
abstract: true,
// ?
})
.state("topic.basics", {
url: "basics/",
views: {
"container": {
templateUrl: "views/basics.html"
}
}
})
.state("topic.payments", {
url: "payments/",
views: {
"container": {
templateUrl: "views/payments.html"
}
}
});
$urlRouterProvider
.when("/topic/", "/topic/basics/")
.otherwise("/");
You are almost there, but because the view target is not a parent, but index.html, we have to use aboslute naming
.state("topic.basics", {
url: "basics/",
views: {
// instead of this, which targets the parent
// "container": {
// we need this, where string empty after # means root/index.html
"container#": {
templateUrl: "views/basics.html"
}
}
})
.state("topic.payments", {
url: "payments/",
views: {
// "container": {
"container#": {
templateUrl: "views/payments.html"
}
See
View Names - Relative vs. Absolute Names
Behind the scenes, every view gets assigned an absolute name that follows a scheme of viewname#statename, where viewname is the name used in the view directive and state name is the state's absolute name, e.g. contact.item. You can also choose to write your view names in the absolute syntax.
For example, the previous example could also be written as:
.state('report',{
views: {
'filters#': { },
'tabledata#': { },
'graph#': { }
}
})
Make the base home state abstract and remove the / in front of the /topic you already use this in the base route.
$stateProvider
.state("home", {
name: 'home',
abstract: true,
url: "/"
})
.state("topic", {
name: 'home.topic',
url: "topic/"
})
.state("topic.basics", {
url: "basics/",
name: 'home.topic.basics'
views: {
"container": {
templateUrl: "views/basics.html"
}
}
})
.state("topic.payments", {
url: "payments/",
name: 'home.topic.payments',
views: {
"container": {
templateUrl: "views/payments.html"
}
}
});
$urlRouterProvider.otherwise("/");

Same html page for different tabs in Angular UI Router

My angular app is routed as following:
$stateProvider
// setup an abstract state for the tabs directive
.state('tab', {
url: "/tab",
abstract: true,
templateUrl: "templates/tabs.html"
})
// Each tab has its own nav history stack:
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab-dotnet.html',
controller: 'QuestionsCtrl'
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab-sql.html',
controller: 'QuestionsCtrl'
}
}
})
The above two routes use the same controller but different html pages.
Since both the pages are same, I want to have a single html page in my application instead of two different tab-sql and tab-dotnet pages.
But I will need a differentiation variable to be injected to the controller when selecting the tabs.
Basically I need something like this:
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
type: 'dotnet' // so that i get this type in my Controller
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
type: 'sql'
}
}
})
How to achieve this?
You can pass data to controllers in a state using resolve.
.state('tab.dotnet', {
url: '/dotnet',
views: {
'tab-dotnet': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
resolve: {
type: 'dotnet';
}
}
}
})
.state('tab.sql', {
url: '/sql',
views: {
'tab-sql': {
templateUrl: 'templates/tab.html',
controller: 'QuestionsCtrl',
resolve: {
type: 'sql';
}
}
}
})
https://github.com/angular-ui/ui-router/wiki#resolve

Resources