I have this code:
angular.module("App").config(function($stateProvider, $locationProvider, $injector) {
$stateProvider
.state("member", {
url: "/member",
abstract: true
})
.state("member.list", {
url: "/list",
views: {
"" : {
templateUrl: "/js/angular/partials/member/list.html?" + Math.random(),
controller: 'MemberController'
}
}
});
});
If I change it to:
angular.module("App").config(function($stateProvider, $locationProvider, $injector) {
$stateProvider
.state("member", {
url: "/member/list",
views: {
"" : {
templateUrl: "/js/angular/partials/member/list.html?" + Math.random(),
controller: 'MemberController'
}
}
});
});
And I do
$state.go("member");
It works ok. Loads the html and parse it to the main view, but with the first version and doing
$state.go("member.list");
It does not parse the html to the main view. It does load the html (I can see it at the debugger) but the html is not placed at the view. What am I doing wrong?
EDIT 1
I found this but this is not really helpful, because I'm doing it programmatically, not with html :(
EDIT 2
Fiddle not working:
http://jsfiddle.net/8ET4L/
Fiddle working:
http://jsfiddle.net/FFx95/
EDIT 3
Fix:
angular.module("App").config(function($stateProvider, $locationProvider, $injector) {
$stateProvider
.state("member", {
url: "/member",
abstract: true,
template: "<div ui-view />"
})
.state("member.list", {
url: "/list",
views: {
"" : {
templateUrl: "/js/angular/partials/member/list.html?" + Math.random(),
controller: 'MemberController'
}
}
});
});
As documentation says:
Remember: Abstract states still need their own <ui-view/> for their
children to plug into. So if you are using an abstract state just to
prepend a url, set resolves/data, or run an onEnter/Exit function,
then you'll additionally need to set template: "<ui-view/>".
Which means you have to have:
<div ng-app="App" ng-controller="AppCtrl">
<div ui-view>
<div ui-view>
this is the main view
</div>
</div>
</div>
in your fiddle. See my updated example.
Alternatively you can declare it on the state definition:
.state("member", {
url: "/member",
abstract: true,
template: "<div ui-view/>"
})
See another fiddle.
Related
http://plnkr.co/edit/i9qhqKZrbxUfsrAOKmMD
I have a basic hello world setup for a header/container/footer in AngularJs however I can't get the footer to load. The header/container is loading fine.
Here's my javascript:
angular.module('app', ['app.controllers', 'ui.router']).config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('root', {
url: '',
abstract: true,
views: {
'header': {
templateUrl: 'pages/header/header.html',
controller: 'HeaderController'
},
'footer': {
templateurl: 'pages/footer/footer.html'
}
}
})
.state('root.home', {
url: '/',
views: {
'container#': {
templateUrl: 'pages/home/home.html',
controller: 'HomeController'
}
}
})
.state('root.about', {
url: '/about',
views: {
'container#': {
templateUrl: 'pages/about/about.html'
}
}
});
$urlRouterProvider.otherwise('/');
});
angular.module('app.controllers', [])
.controller('HeaderController', headerController)
.controller('HomeController', homeController);
Here's my implementation on HTML:
<header ui-view="header">
</header>
<div ui-view="container">
</div>
<footer ui-view="footer">
</footer>
Changing them all to divs does not help.
There are no errors in Javascript console.
Header.html
<h1>Header</h1>
Home.html
<h1>Home</h1>
Footer.html
<h1>Footer</h1>
Page display:
Header
Home
The reason it is not working is because of a small typo in your code. This definition:
'footer': {
templateurl: 'pages/footer/footer.html'
}
should be:
'footer': {
templateUrl: 'pages/footer/footer.html'
}
This is a great example of bad design (on the part of ui-router). They could have performed checks of validity on requested views if there is no template or controller. However, I think it more importantly shows the shortcomings of allowing objects to be passed to functions. If templateUrl was a parameter to a function, this sort of problem would never arise.
Updated plunkr.
Replace templateurl with templateUrl.
I am creating a web app to help students in science, history and math. When you first land on the site I have a home/landing page. When you click get started I route to /exam/instructions. Each of my steps instructions, math and science our templates that I load into the ui-view="exam-detail". Currently the whole ui-view loads when I navigate to and from instructions through sciences. Ideally I simply want an area for pagination and an area for the subject matter and only want the ui-view="exam-detail" to update with the correct template.
I have not used UI-Router at all and any assistance would be greatly appreciated.
index.html
<div ui-view></div>
state-exam>exam.html
<div class="state-exam">
<nav ui-view="exam-pagination"></nav>
<section ui-view="exam-detail"></section>
</div>
route.js
(function() {
'use strict';
angular
.module('studentPortal')
.config(routeConfig);
function routeConfig($stateProvider, $urlRouterProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'app/main/main.html',
controller: 'MainController',
controllerAs: 'main'
})
.state('exam', {
url: '/exam/:step',
abstract: true,
templateUrl: 'app/state-exam/exam.html',
controller: 'ExamController',
controllerAs: 'examController',
})
.state('exam.instructions', {
url: '/instructions',
views: {
'exam-pagination':{
templateUrl: 'app/state-exam/exam-pagination.html'
},
'exam-detail' : {
templateUrl: 'app/state-exam/exam-instructions.html'
}
}
})
.state('exam.math', {
url: '/math',
views: {
'exam-pagination':{
templateUrl: 'app/state-exam/exam-pagination.html'
},
'exam-detail' : {
templateUrl: 'app/state-exam/exam-math.html'
}
}
});
$urlRouterProvider.otherwise('/');
}
})();
There is a working plunker
There is a similar Q & A in fact, with working plunker:
Angular UI Router - Nested States with multiple layouts
Solution here, is to move the static view from child to parent. It won't be reloaded for each child (view is reloaded only if parent state is changed). We will use absolute naming (see included links for more details)
So this is the code adjustment
.state('exam', {
url: '/exam/:step',
abstract: true,
// the root view and the static pagination view
// will be defined here, so we need views : {}
views: {
'':{
templateUrl: 'app/state-exam/exam.html',
controller: 'ExamController',
controllerAs: 'examController',
},
// absolute naming targets the view defined above
'exam-pagination#exam':{
templateUrl: 'app/state-exam/exam-pagination.html'
},
}
})
.state('exam.instructions', {
url: '/instructions',
views: {
// 'exam-pagination':{}, // defined in parent
'exam-detail' : {
templateUrl: 'app/state-exam/exam-instructions.html'
}
}
})
.state('exam.math', {
url: '/math',
views: {
// 'exam-pagination':{}, // defined in parent
'exam-detail' : {
templateUrl: 'app/state-exam/exam-math.html'
}
}
});
Also check this to get more details about absolute view naming
Angular UI router nested views
Angular-UI Router: Nested Views Not Working
The working example is here
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
I've seen a few questions like this, so forgive me if I've overlooked a crucial detail from them.
When I load http://localhost:8000/characters/#/mages/detail/3 I get redirected to my 'otherwise' url: $urlRouterProvider.otherwise("/users");
But my state provider (if I've understood this correctly) should load the correct page:
$stateProvider
.state('users', {
url: "/users",
templateUrl: DjangoProperties.STATIC_URL + "partials/users.html"
})
.state('users.list', {
url: "/list",
templateUrl: DjangoProperties.STATIC_URL + "partials/users.list.html",
controller: 'UserListCtrl'
})
.state('users.detail', {
url: "/detail/{userID:int}",
templateUrl: DjangoProperties.STATIC_URL + "partials/users.detail.html",
controller: 'UserDetailCtrl'
})
.state('mages', {
url: "/mages",
templateUrl: DjangoProperties.STATIC_URL + "partials/mages.html"
})
.state('mages.list', {
url: "/list",
templateUrl: DjangoProperties.STATIC_URL + "partials/mages.list.html",
controller: 'MageCtrl'
})
.state('mages.detail', {
url: "/detail/{mageID:int}",
views:{
"#mage.detail": {
templateUrl: DjangoProperties.STATIC_URL + "partials/mages.detail.html",
controller: 'MageCtrl',
},
"characteristics#mage.detail": {
templateUrl: DjangoProperties.STATIC_URL + "common_partials/characteristics.html"
},
"attributes#mage.detail": {
templateUrl: DjangoProperties.STATIC_URL + "common_partials/attributes.html"
},
"skills#mage.detail": {
templateUrl: DjangoProperties.STATIC_URL + "common_partials/skills.html"
},
"spells#mage.detail": {
templateUrl: DjangoProperties.STATIC_URL + "partials/spells.html"
},
}
});
}]);
Here is my mages.html:
<h1>Mages</h1>
<hr/>
<a ui-sref="mages.list">Show List</a>
<div ui-view></div>
and my mages.detail.html
<h4>{{mage.name}}</h4>
<div ui-view>
<div ui-view="characteristics"></div>
<div ui-view="attributes"></div>
<div ui-view="skills"></div>
<div ui-view="spells"></div>
</div>
None of these are loaded, just the default 'list' page.
I feel I've gotten muddled over my view names, but I can't figure out what to do to fix them?
There is another working plunker
In case we want to have only two levels
mages
mages.list
mages.deatil
We have to adjust the state def like this:
.state('mages', {
url: "/mages",
templateUrl: DjangoProperties.STATIC_URL + "partials/mages.html"
})
.state('mages.list', {
url: "/list",
templateUrl: DjangoProperties.STATIC_URL + "partials/mages.list.html",
controller: 'MageCtrl'
})
.state('mages.detail', {
url: "/detail/{mageID:int}",
views:{
"": {
templateUrl: DjangoProperties.STATIC_URL + "partials/mages.detail.html",
controller: 'MageCtrl',
},
"state#mages.detail" : {
templateUrl: "tpl.html",
},
"characteristics#mages.detail": {
//templateUrl: DjangoProperties.STATIC_URL + "common_partials/characteristics.html"
template: "common_partials/characteristics.html",
},
"attributes#mages.detail": {
//templateUrl: DjangoProperties.STATIC_URL + "common_partials/attributes.html"
template: "common_partials/attributes.html"
},
"skills#mages.detail": {
//templateUrl: DjangoProperties.STATIC_URL + "common_partials/skills.html"
template: "common_partials/skills.html"
},
"spells#mages.detail": {
//templateUrl: DjangoProperties.STATIC_URL + "partials/spells.html"
template: "partials/spells.html"
},
}
});
And the mages.list.html will be now like this (no place for child detail)
<h3>The mages list</h3>
<h4>{{mage.name}}</h4>
<li>mages/detail/1
<li>mages/detail/2
<li>mages/detail/3
<li>mages/detail/4
And the mages.detail.html wil be:
<div >
<a ui-sref="mages.list">back to list</a>
<div ui-view="state"></div>
<div ui-view="characteristics"></div>
<div ui-view="attributes"></div>
<div ui-view="skills"></div>
<div ui-view="spells"></div>
</div>
check it here
I tried to adjust your settings, and show you one possible way.
There is a working plunker
So, these would be new states mages:
.state('mages', {
url: "/mages",
templateUrl: DjangoProperties.STATIC_URL + "partials/mages.html"
})
.state('mages.list', {
url: "/list",
templateUrl: DjangoProperties.STATIC_URL + "partials/mages.list.html",
controller: 'MageCtrl'
})
where detail is child of the list
.state('mages.list.detail', {
url: "/detail/{mageID:int}",
views:{
/*
"#mage.detail": {
templateUrl: DjangoProperties.STATIC_URL + "partials/mages.detail.html",
controller: 'MageCtrl',
},
*/
"" : {
templateUrl: "tpl.html",
},
"characteristics#mages.list": {
//templateUrl: DjangoProperties.STATIC_URL + "common_partials/characteristics.html"
template: "common_partials/characteristics.html",
},
"attributes": {
//templateUrl: DjangoProperties.STATIC_URL + "common_partials/attributes.html"
template: "common_partials/attributes.html"
},
"skills": {
//templateUrl: DjangoProperties.STATIC_URL + "common_partials/skills.html"
template: "common_partials/skills.html"
},
"spells": {
//templateUrl: DjangoProperties.STATIC_URL + "partials/spells.html"
template: "partials/spells.html"
},
}
});
And these are two basic tmplates
mages.html (as it was, no change):
<h1>Mages</h1>
<hr/>
<a ui-sref="mages.list">Show List</a>
<div ui-view></div>
The mages.list.html
<h3>The mages list</h3>
<h4>{{mage.name}}</h4>
<li>mages/list/detail/1
<li>mages/list/detail/2
<li>mages/list/detail/3
<li>mages/list/detail/4
<hr />
<div >
<div ui-view=""></div>
<div ui-view="characteristics"></div>
<div ui-view="attributes"></div>
<div ui-view="skills"></div>
<div ui-view="spells"></div>
</div>
It is now containing the links to detail and also contains the anchor for detail views
I would like to show how the view naming is working. There is a working plunker
So, let's have this index.html:
<H1><ui-view name="title" /></H1>
<ul>
<li><a ui-sref="parent">parent</a>
<li><a ui-sref="parent.child">parent.child</a>
</ul>
<div ui-view=""></div>
There is one unnamed view, and one named (title). We have two states. and both will be targeting this 'title' view:
.state('parent', {
...
views : {
...
"title" : {
template : "parent is setting title inside of index.html"
}
}
})
.state('parent.child', {
...
views : {
...
"title#" : {
template : "CHILD is setting title inside of index.html"
},
}
})
What we can see, is that parent calls the view "title" (relative name). The reason is, that index.html (root view) is its parent. The absolute name would work as well (and in fact is created behind the scene): "title#"
On the other hand, child must use absolute naming, because it targets view which is not part of the parent... it is grand-parent (root). So the view name is: "title#"
Now, child template, injected into parent is:
<div>
<h4>Child</h4>
<hr />
View A:
<div ui-view="viewA" ></div>
View B:
<div ui-view="viewB" ></div>
</div>
and that means that child state definition now will be:
.state('parent.child', {
...
views : {
"" : {
templateUrl: 'tpl.child.html',
controller: 'ChildCtrl',
},
"viewA#parent.child" : {
template : "<h5>child content of the view A</h5>"
},
"viewB#parent.child" : {
template : "<h5>child content of the view B</h5>"
}
... // title into the root
}
})
So firstly we injected child template into parent unnamed view "": {...
And next we inject some views (existing inside of this child) with absolute naming === using the child full state name "viewB#parent.child"
Check it in action here
Documentation:
Multiple Named Views
...
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.
I've got a config function:
function config($stateProvider,$locationProvider) {
$locationProvider.html5Mode(true);
$stateProvider
.state('projectsWs.tasks', {
url: "/tasks",
views: {
"mainView": {
templateUrl: "/app/projects/templates/index.php"
},
"innerView": {
templateUrl: "/app/projects/templates/tasks.php",
controller: tasksCtrl,
controllerAs:'tasks'
}
}
})
.state('projectsWs.tasks.detail', {
url: "/:taskId",
views: {
"mainView#": {
templateUrl: "/app/projects/templates/index.php"
},
"innerView#mainView": {
templateUrl: "/app/projects/templates/tasks.php",
controller: function($stateParams) {
console.log('innerViewCtrl', $stateParams);
}
}
}
});}
InnerView is inside mainView.
When I've got url like /projects-ws/tasks, tasksCtrl function works as expected. But when I've got url with an id, i.e. /projects-ws/tasks/32, I don't see any output, but I expect innerViewCtrl output, that's the problem I got. I think I've got a problem with absolute/relative views, but I've allready tried all combinations and it still don't work.
UPDATE:
So now I've got following state:
state('projectsWs.tasks.detail', {
url: "/:taskId",
views: {
"mainView#": {
templateUrl: "/app/projects/templates/index.php",
controller: function($stateParams) {
console.log('mainViewctrl', $stateParams);
}
},
"innerView": {
templateUrl: "/app/projects/templates/tasks.php",
controller: function($stateParams) {
console.log('innerViewctrl', $stateParams);
}
}
}
})
as Radim Köhler said. It outputs mainViewctrl Object {taskId: "32"}, but how can I reach $stateParams.taskId from innerView now?
Absolute naming with UI-Router works a bit differntly then you've used it
.state('projectsWs.tasks.detail', {
url: "/:taskId",
views: {
"mainView#": {
templateUrl: "/app/projects/templates/index.php"
},
// this won't work, because the part after #
// must be state name
"innerView#mainView": {
// so we would need this to target root, index.html
"innerView#": {
// or this to target nested view inside of a parent
"innerView": {
// which is the same as this
"innerView#projectsWs.tasks": {
Check the:
View Names - Relative vs. Absolute Names
small cite:
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.
I created a working example here, and the states are like this
$stateProvider
.state('projectsWs', {
template: '<div ui-view="mainView" ></div>' +
'<div ui-view="innerView" ></div>',
})
$stateProvider
.state('projectsWs.tasks', {
url: "/tasks",
views: {
"mainView": {
//templateUrl: "/app/projects/templates/index.php"
template: "<div>main view tasks </div>",
},
"innerView": {
//templateUrl: "/app/projects/templates/tasks.php",
template: "<div>inner view tasks </div>",
}
}
})
.state('projectsWs.tasks.detail', {
url: "/:taskId",
views: {
"mainView#projectsWs": {
//templateUrl: "/app/projects/templates/index.php"
template: "<div>main view task {{$stateParams | json }} </div>",
},
"innerView#projectsWs": {
//templateUrl: "/app/projects/templates/tasks.php",
template: "<div>inner view task {{$stateParams | json }} </div>",
}
}
});
What we can see is, that the grand parent projectsWs is injecting into index.html (root) <div ui-view=""> some template, with two named anchors:
template: '<div ui-view="mainView" ></div>' +
'<div ui-view="innerView" ></div>',
this are then used in list and detail states, with relative resp absolute names
Check it here in action