I'm having an issue with nested states in UI-Router. I have a two states, and upon button click it should transition to another state, and the url changes, but the template does not. Here is my code for the state logic:
$stateProvider.state('accounts', {
url: '/accounts',
views: {
'menu': {
templateUrl: 'templates/menu.html',
controller: 'MenuController'
},
'main': {
templateUrl: 'templates/accounts.html',
controller: 'AccountsController'
}
}
});
$stateProvider.state('accounts.detail', {
url: '/:accountID',
views: {
'main': {
templateUrl: 'templates/accounts.detail.html',
controller: 'AccountsDetailController'
}
}
});
And my button logic: $state.go('accounts.detail', { accountID : account.accountID});
Both of my views are wrapped up in ui-view tags. All other root states work correctly (/home, /orders) however /accounts/:accountID will not trigger the template to load and transition. Any insight will be greatly appreciated.
<ion-view /> is not the equivalent of <ui-view />, in Ionic Framework it is just a container to insert header/footer bars and content.
use <ion-nav-view /> http://ionicframework.com/docs/api/directive/ionNavView/
and reference by name this nested view in your parent view: <ion-nav-view name="main" />
My issue was that I wasn't referring to my views correctly. Because of how they are nested, I needed to use the absolute name to cause the view to show. The linked UI-router documentation describes my issue.
https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views#view-names---relative-vs-absolute-names
Related
I've been working with Angular for a year or 2 now, but this is my first project using ui-router. I'm running into a few issues with views and sub-views. The app is a standard left-side menu bar, with the views on the right changing depending on what's clicked in the menu bar.
On index.html
<body>
<div ui-view></div>
</body>
In the config.js file, which defines the routes
.state("dashboard", {
url: "/dashboard",
templateUrl: "components/dashboard/dashboard.html",
data: {
pageTitle: "Dashboard",
requiresLogin: false
}
})
.state("dashboard.welcome", {
url: "/welcome",
templateUrl: "components/welcome/welcome.html",
data: {
pageTitle: "Welcome",
requiresLogin: false
}
})
In the dashboard.html file
<div class="dashboard">
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 col-md-8">
<div ui-view>
The /dashboard path loads correctly, and will load the left-side navigation bar with a blank right side. But changing the state to dashboard.welcome (/welcome) will not load the welcome.html template.
Whenever working with ui-router you need to understand that the concept of states is different from routes. When you define a sub-state, its defined relative to its parent state. In your scenario dashboard.welcome is defined as a child state of dashboard. The routes to substate is relative to the parent and is {parent url}/{child url}. Hence you should use either of the below 2 to route to that state:
Using $state.go change the state by specifying state name
$state.go('dashboard.welcome');
Using $location.path change the route by specifying url
$location.path('/dashboard/welcome');
It sounds like you want links to /welcome to be for state dashboard.welcome. Here is a plunker showing how this can be done. I show two sets of dashboard and welcome states. The first set of states (dashboard & welcome) shows that /dashboard/welcome will bring you to the dashboard.welcome state.
The second set (dashboard2 & welcome2) shows that /welcome will go to state dashboard2.welcome2. I believe this is what you were looking for.
If you hover over the links you can see where they will take you.
https://plnkr.co/edit/AVKPFa?p=info
Nested routes in ui-router get nested urls. I would however recommend using named-views for this kind of structure. You can find more info about it here:
https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views
The gist of it is: you can specify a named component (ui-view) for your left menu navigation and another one for content, which gives you much more control down the line, because named components can be overwritten in child states or they can keep the default template, depending on your needs.
Example:
.state('root', {
url: '',
abstract: true,
views: {
'header': {
templateUrl: 'templates/partials/header.html',
controller: 'headerCtrl'
},
'logo': {
templateUrl: 'templates/partials/logoView.html'
},
'footer':{
templateUrl: 'templates/partials/footer.html',
controller: 'footerCtrl'
}
}
})
.state('root.login', {
url: '/login',
views: {
'header#': {
template: ''
},
'container#': {
templateUrl: 'templates/login.html',
controller: 'loginController'
}
}
})
.state('root.report', {
url: '/report',
views: {
'container#': {
templateUrl: 'templates/eu_dashboard.html',
controller: 'reportController'
}
}
})
And in your index.html:
<div ui-view="logo"></div>
<div ui-view="header"></div>
<div id="mainView" ui-view="container"></div>
<div ui-view="footer"></div>
My ionic back button doesn't do anything when it is being clicked even though, when I print out the version history, it shows that there is a back view. Also for some reason $ionicHistory.enabledBack() is returning false, even though the back view exists and the back view and current view have the same id. Does anyone know how to fix the problem?
Here's a snapshot of the console.
Use ui-router nested views to create states that will replace an ion-nav-view tag in the HTML.
Use ion-view, not ion-nav-view, inside the template html for each nested view.
Example:
Parent (Nav) View HTML:
<ion-nav-view name="navView"></ion-nav-view>
Nested View Level 1 HTML:
<ion-view view-title="Nested View Level 1">
<ion-content></ion-content>
</ion-view>
Nested View Level 2 HTML:
<ion-view view-title="Nested View Level 2">
<ion-content></ion-content>
</ion-view>
ui-router:
$stateProvider
.state('app.navView', {
url: '/nav-view',
views: {
'menuContent': {
templateUrl: 'app/navView.html',
controller: 'NavViewCtrl as vm'
}
}
})
.state('app.nestedViewL1', {
url: '/nested-view-L1',
views: {
'navView': {
templateUrl: 'app/nestedViewL1.html',
controller: 'NestedView1CtrL1 as vm'
}
}
})
.state('app.nestedViewL2', {
url: '/nested-view-L2',
views: {
'navView': {
templateUrl: 'app/nestedViewL2.html',
controller: 'NestedViewL2Ctrl as vm'
}
}
})
I'm new to using Angular UI Router and I seem to be having difficulty being able to update a parent view from it's child view.
I have the following HTML structure (restructured for easier reading, obviously views are in separate html files).
<div ui-view="main">
{ main content }
<div ui-view="tab">
{ tabbed content }
</div>
</div>
Inside tab I have the following sref:
<span ui-sref="silverstone.platforms.view({_id: platform._id})">{{platform.name}}</span>
And here are my states: (I'm using webpack, hence require)
$stateProvider
.state('silverstone', {
url: '/silverstone',
views: {
'main': {
controller: 'SilverstoneCtrl',
template: require('./templates/index.html')
}
}
});
$stateProvider
.state('silverstone.platforms', {
url: '/platforms',
views: {
'tab': {
controller: 'SilverstoneCtrl',
template: require('./templates/platforms.html')
}
}
});
$stateProvider
.state('silverstone.platforms.view', {
url: '/:_id',
views: {
'main': {
controller: 'SilverstoneCtrl',
template: require('./templates/platform-view.html')
}
}
});
When the above sref is clicked, the "main" view needs to be updated. The URL is updating but the views aren't...?
I was missing # in my silverstone.platforms.view state to explicitly address the parent view.
$stateProvider
.state('silverstone.platforms.view', {
url: '/:_id',
views: {
'main#': {
controller: 'SilverstoneCtrl',
template: require('./templates/platform-view.html')
}
}
});
Use reload: true parameter in yout ui-sref links like this.
ui-sref="silverstone.platforms.view({_id: platform._id})" ui-sref-opts="{reload: true}"
Edit:
Maybe your problem are caused by nested states combined with flat template structure.
Other solution may be to properly nest your templates, as states.
For example we have states app and app.substate, then we have two templates for both states. Tempalte of app state contains ui-view directive. (that means every state contains new ui-view directive for injecting of substate template). States are nested by default, this would represent appropriately nested templates.
I would like to make a bootstrap tabset with each tab having it's own controller. Can anyone point me in which direction I should go.
Currently I have made several difference controllers, which I would like to be used in a tabset instead of having them displayed as a different route.
I know I could fake it by having the tabset in the difference controller templates displaying the given controllers tab as active, but I would like to be able to have a main TabController with several child controllers (for each tab)
If you are using angular ui router you can use nested states to do this.
Create an abstract state with a view that contains the tabs and a nested ui-view
Create a child state for each of your tabs, each inheriting from the abstract state
Each child state can set the content of the nested ui-view, and define a controller
$stateProvider.state( 'tabs', {
abstract: true,
url: 'tabs',
views: {
"tabs": {
controller: 'TabsCtrl',
templateUrl: 'tabs.html'
}
}
})
.state('tabs.tab1', {
url: '', //make this the default tab
views: {
"tabContent": {
controller: 'Tab1Ctrl',
templateUrl: 'tab1.html'
}
}
})
.state('tabs.tab2', {
url: '/tab2',
views: {
"tabContent": {
controller: 'Tab2Ctrl',
templateUrl: 'tab2.html'
}
}
});
Why don't you put a directive on each tab that has it's own controller? If you are using 1.x. Separate your code out by directive not tabs
Sorry if the title of this is confusing.
I'm converting a template I purchased into an angular.js app.
I want to use different modules to organize the app.
I'm also using version 0.2.5 of angular-ui-router which allows routing with separate modules.
All is well except the template I'm using looks like this:
<div>Global Nav Bar</div>
<div>Content that changes with different states right below Nav Bar</div>
<div class="wrapsContentAndPushesToBottom">
<div>Content that changes with different states at
bottom of page thanks to parent div's class</div>
<div>Global Footer also on bottom of page due
to parent div's class</div>
</div>
I'm having a hard time getting that global footer to work because of that parent wrapping div.
Can someone help me get this to work?
UPDATE:
I can't get suggested ng-include to work with my plunkr example: http://plnkr.co/edit/dgNkHX
I also can't it working using a named view for the footer: http://plnkr.co/edit/BO8NDO
I think you're looking for ng-include. http://docs.angularjs.org/api/ng.directive:ngInclude
That will enable you to extract that global footer out to a separate file and just include it in your template.
<div ng-include src="'globalFooter.tpl.html'"></div>
Try something like this:
.state('root', {
abstract: true,
views: {
'#': {
},
'sideBar#': { templateUrl: 'views/sidebar.html', controller: 'SideBarCtrl' },
'header#': { templateUrl: 'views/header.html' },
'footer#': { templateUrl: 'views/footer.html' }
}
})
.state('main', {
url: '/',
parent: 'root',
views: {
'#': { templateUrl: 'views/main_content.html', controller: 'MainCtrl' }
}
})
This is working for me.. I have a global footer.