Could someone give a hint on ui-view?
I have one main ui-view and then two nested views, but for some reason these two are not getting loaded.
$stateProvider
.state('index',{
url:'',
templateUrl: './app/modules/main.html'
})
.state('index.feed',{
parent:'index',
templateUrl: './app/modules/feed.html'
})
.state('index.status',{
parent: 'index',
templateUrl: './app/modules/status.html'
});
The main page is loading but the two other views not
in my main.html I have:
<div class="voucher-display" ui-view="index.feed"></div>
<div class="feed" ui-view="index.feed"></div>
I just get an empty file.
The value you pass to ui-view in your html is not the name of the state, it should be the name of the view.
Is the html in feed.html and status.html supposed to replace or be displayed along with main.html? Either scenario will change the solution, but assuming you always want main.html, and want to display the feed.html and status.html where their respective nested views are selected, you'd do something like this:
.state('index', {
url: '/',
views: {
'main': {
templateUrl: './app/modules/main.html'
}
}
})
.state('index', {
views: {
'main': {
templateUrl: './app/modules/main.html',
},
'detail': {
templateUrl: './app/modules/feed.html'
}
}
})
.state('index.status', {
views: {
'main': {
templateUrl: './app/modules/main.html',
},
'detail': {
templateUrl: './app/modules/status.html'
}
}
});
And in your html you'd need two div tags that map the view.
<div ui-view="main"></div>
<div ui-view="detail"></div>
Now main.html should always show up in the first div, and feed.html or status.html, when their states are active, will show up in the second div.
Here is the docs for the ui-view directive, and here is a good blog post about ui-view.
After a couple of attempts, this worked to load the nested:
$stateProvider
.state('index', {
url: '',
views: {
'main': {
templateUrl: './app/modules/main.html'
},
'status#index': {
templateUrl: './app/modules/status.html'
},
'feed#index':{
templateUrl: './app/modules/feed.html'
}
}
})
index.html has:
<main ui-view="main"></main>
and inside the main.html I have:
<div class="voucher-display" ui-view="feed"></div>
<aside ui-view='status'></aside>
but now I got another problem, if I want to load another ui-view from my index.html, what should I do? because this does not work:
.state('clients',{
url:'/clients',
templateUrl: './app/modules/clients.html'
});
Related
I would like to have a common state with all the common views like the header and the sidebar, and a template where I would like to load different views that can change when the state is changing.
I have an index HTML file like this:
...
<div ui-view="header"></div>
<div ui-view="sidebar"></div>
<div class="container">
<div class="wrapper">
<div ui-view="content"></div>
</div>
</div>
...
While the AngularJS config is something like this:
$stateProvider
.state('mainCommonState', {
url: '',
abstract: true,
views: {
header: {
templateUrl: 'app/common/header.html',
controller: 'headerCtrl',
controllerAs: 'vm'
},
sidebar: {
templateUrl: 'app/common/sidebar.html',
controller: 'sidebarCtrl',
controllerAs: 'vm'
},
content: {}
},
resolve: {
apiEnvironment: function ($q, environmentApiService) {
var deferred = $q.defer();
deferred.resolve(environmentApiService.getApiEnvironment());
return deferred.promise;
}
}
})
.state('first-page-content', {
url: '/first-page-content',
parent: 'mainCommonState',
views: {
content: {
templateUrl: 'app/components/first-page-content.html'
controller: 'firstPageCtrl',
controllerAs: 'vm'
}
}
})
.state('second-page-content', {
url: '/second-page-content',
parent: 'mainCommonState',
views: {
content: {
templateUrl: 'app/components/second-page-content.html'
controller: 'secondPageCtrl',
controllerAs: 'vm'
}
}
})
.state('third-page-content', {
url: '/third-page-content',
parent: 'mainCommonState',
views: {
content: {
templateUrl: 'app/components/third-page-content.html'
controller: 'thirdPageCtrl',
controllerAs: 'vm'
}
}
})
For some reason this is not working: I have an empty view instead of the 3 templates that I would like to show in the content ui-view.
If I define a template (even a blank template) inside the the abstract state, the view that is always showing is the one inside the abstract state mainCommonState.
Where am I wrong?
1st Edit: UPDATE Following the first answer
Following the suggestion from Chris T, I have updated my code, but there still something missing.
I have created a Plunker so you can help me fixing the issues.
2nd Edit
Following the suggestions from Chris T, I have updated the code using the absolute path for the content view and now the contents are switching correctly.
I have updated the Plunker accordingly to that and introduced a new level of nesting view (tabs in the first page), and I would like to have the first tab active when the first page content is loaded.
If I follow these solutions and set empty the url of the first page and set it to the first tab instead, this is not working.
Any suggestions?
Your views are targeting the wrong named ui-view.
.state('second-page-content', {
url: '/second-page-content',
parent: 'mainCommonState',
views: {
content: {
templateUrl: 'app/components/second-page-content.html'
controller: 'secondPageCtrl',
controllerAs: 'vm'
}
}
})
In this snippet, it targets the ui-view named content from the parent state which is mainCommonState. However, the content ui-view was not created in the mainCommonState. It was created in the root template.
Change your view declarations to target the view at the correct state, for example this targets the content view at the root state (which is named empty string):
.state('second-page-content', {
url: '/second-page-content',
parent: 'mainCommonState',
views: {
'content#': {
templateUrl: 'app/components/second-page-content.html'
controller: 'secondPageCtrl',
controllerAs: 'vm'
}
}
})
In ui-router 1.0 and higher you can also use absolute ui-view names by prefixing with an exclamation
.state('second-page-content', {
url: '/second-page-content',
parent: 'mainCommonState',
views: {
'!content': {
templateUrl: 'app/components/second-page-content.html'
controller: 'secondPageCtrl',
controllerAs: 'vm'
}
}
})
Read more about view targeting in the UI-Router views guide:
https://ui-router.github.io/guide/views#view-name-only
I have seen a design interface here, and I liked it.
I was doing it with AngularJS, and ui-router which allows to have multiple views on a single page.
I have an issue for smartphone, because I want to display only one view, not two like tablets/desktops.
Question :
What would be the best way to display only one view for small screens, and two for larger screens ?
I had basic ideas :
Idea 1 (not so so good) : I was thinking to create multiple routes, then route to one or the other route depending the screen size.
Inside angular config
app.config(function($stateProvider) {
$stateProvider
.state('listForLargeScreens', {
url: "/listForLargeScreens",
views: {
"primary": { templateUrl: "list.html" },
"secondary": { templateUrl: "detail.html" }
}
})
.state('listForSmallScreens', {
url: "/listForSmallScreens",
views: {
"primary": { templateUrl: "list.html" }
}
})
...;
Inside a random controller
app.controller('RandomCtrl', function ($scope, $state) {
$scope.changePage = function () {
if (isLargeScreen) {
$state.go('indexForLargeScreens');
} else {
$state.go('indexForSmallScreens');
}
}
});
Problem : this idea seems to me too "dirty" for maintaining.
Idea 2 : I was thinking to declare primary and secondary views, then I could hide with CSS the secondary one with CSS :
Inside angular config
app.config(function($stateProvider) {
$stateProvider
.state('list', {
url: "/",
views: {
"primary": { templateUrl: "list.html" },
"secondary": { templateUrl: "detail.html" }
}
})
.state('detail', {
url: "/detail/:id",
views: {
"secondary": { templateUrl: "list.html" },
"primary": { templateUrl: "detail.html" }
}
})
...;
Inside html
<div ui-view="main"></div>
<div ui-view="secondary"></div> <!-- For small screens, hide this view with CSS -->
Problem : different URLS can have the same views, but with inverted priorities, see :
So, on small screens, it could work, but on larger screens, in some URLs, views can be inverted, (see the image above), so in HTML, list.html and detail.html templates will be inverted too.
It could solve the problem if I could invert <div ui-view="primary"></div> and <div ui-view="secondary"></div> on some views...
I've just found on scotch.io a piece of code which is the key for that problem.
The idea 2 on the question was almost the answer, but I had a problem with different URLs which where using same views, but with inverted priorities.
ui-router allows with multiple named views, to get ancestors, so I have to create a piece of html which declares ui-views :
Inside angular config :
$stateProvider.state('list', {
url: '/list',
views: {
'': { templateUrl: 'partial-list.html' },
'primary#list': {
templateUrl: 'list.html',
controller: 'ListCtrl as ctrl'
},
'secondary#list': {
templateUrl: 'detail.html',
controller: 'DetailCtrl as ctrl'
}
}
}).state('detail', {
url: '/detail/:id',
views: {
'': { templateUrl: 'partial-detail.html' },
'primary#list': {
templateUrl: 'detail.html',
controller: 'DetailCtrl as ctrl'
},
'secondary#list': {
templateUrl: 'list.html',
controller: 'ListCtrl as ctrl'
}
}
});
Inside partial-list.html :
<div ui-view="primary"></div>
<div ui-view="secondary" class="hide-it-for-small-screens"></div>
Inside partial-detail.html :
<div ui-view="secondary" class="hide-it-for-small-screens"></div>
<div ui-view="primary"></div>
It works ! :)
I just started migrating to AngularJS and I'm already having problems with the $stateProvider from the angular-ui/ui-router framework. This is what I have so far:
angular
.module('testApp', ['ui.router'])
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("/index/home");
$stateProvider
.state('index', {
abstract: true,
url: "/index",
template: "parent"
})
.state('index.home', {
url: "/home",
template: "child"
})
})
.controller("MainController", function() {
})
Now, running this script redirects me to http://example.com/#/index/home but it only displays the parent string on the page. The child string is not being shown. From my understanding this should load the first template because we are on the /#/index domain part and then the second because we are on a nested page /#/index/home.
Can someone help me and explain why this is not working as intended?
In your template for the parent you need another <div ui-view></div> in order to render child states.
If you want multiple nested views, you can have multiple ui-view in your parent template. You just have to name them. For example,
parent template:
<h1>parent</h1>
<div ui-view="child1"></div>
<div ui-view="child2"></div>
And you define the child states as follows:
$stateProvider
.state('index', {
abstract: true,
url: "/index",
template: "parent"
})
.state('index.home', {
url: "/home",
views: {
'child1': {
templateURL: "child1.html"
}
}
})
.state('index.home2', {
url: '/home2',
views: {
'child2': {
templateURL: 'child2.html'
}
}
})
*note I used templateURL instead of template. Assuming your app has modular file structure.
I want to give 2 parts of my UI the same controller but still let them have each of their own unique controllers.
$stateProvider
.state('standard.page', {
url: '/:page',
resolve: {
page: function($stateParams) {
...
},
},
views: {
'content': {
templateUrl: '/tmpl/page',
controller: 'controllercontent'
},
'sideMenu': {
templateUrl: '/tmpl/menu',
controller: 'controllermenu',
}
}
})
So I want both content and sideMenu to share a controller. If I add a controller above the views then it requires a new template, I want to use the standard template instead of making a unique template for this state. Any ideas how I can get 3 controllers going in this example? Thanks.
I battled with this at some point in time, and I believe I made a template file that isn't directly accessible (via abstract: true). Here's an example...
.state('standard', {
url: '/standard',
abstract: true,
templateUrl: '/tmpl/standard.html',
controller: 'SharedController'
},
})
.state('standard.page', {
url: '/:page',
resolve: {
page: function($stateParams) {
...
},
},
views: {
'content': {
templateUrl: '/tmpl/page',
controller: 'controllercontent'
},
'sideMenu': {
templateUrl: '/tmpl/menu',
controller: 'controllermenu',
}
}
});
In your tmpl/standard.html file, make sure this exists somewhere within the file:
<div ui-view="sideMenu">
<div ui-view="content">
Hope this points you in the right direction.
WikiApp.config(function config($stateProvider, $urlRouterProvider) {
$stateProvider
.state('revision', {
url: '/wiki',
views: {
"main": {
controller: 'ListCtrl',
templateUrl: 'wiki/wiki.tpl.html'
},
"sidebar-left": {
templateUrl: 'wiki/wiki.sidebar-left.tpl.html'
}
},
data:{ pageTitle: 'List articles' }
})
This is what my Angular bit looks like and this is how I execute it inside of a template (wiki.tpl.html):
<div ui-view="sidebar-left"></div>
Now the main view works fine, but as I try to integrate the sidebar, it doesn't load, what am I doing wrong and how can I use more than one template in a single page like this?
Thank you!
WikiApp.config(function config($stateProvider, $urlRouterProvider) {
$stateProvider
.state('revision', {
url: '/wiki',
views: {
main: {
controller: 'ListCtrl',
templateUrl: 'wiki/wiki.tpl.html'
},
sidebarLeft: {
templateUrl: 'wiki/wiki.sidebar-left.tpl.html'
}
},
data:{ pageTitle: 'List articles' }
})
If you want to use nested templates you should implement that using sub-views. In your current example you are setting both templates as sibling templates.
I suggest you to create 2 states. Abstract view for the main template 'main' and another view 'main.wiki'. Route should be assigned to 'main.wiki' state ant it will inherit parameters from the main view (including template settings).
Hope that's clear.