I am trying to update a part of a view within another view.
But the link keeps overwriting the outer ng-view
How Do I update an ng-view within an ng-view ?
This library should perfectly fit your needs:
http://angular-route-segment.com
Demo site: http://angular-route-segment.com/src/example/
It is much, much simpler to use than ui-router. Sample routes config looks like this:
$routeSegmentProvider.
when('/section1', 's1.home').
when('/section1/prefs', 's1.prefs').
when('/section1/:id', 's1.itemInfo.overview').
when('/section1/:id/edit', 's1.itemInfo.edit').
when('/section2', 's2').
segment('s1', {
templateUrl: 'templates/section1.html',
controller: MainCtrl}).
within().
segment('home', {
templateUrl: 'templates/section1/home.html'}).
segment('itemInfo', {
templateUrl: 'templates/section1/item.html',
controller: Section1ItemCtrl,
dependencies: ['id']}).
within().
segment('overview', {
templateUrl: 'templates/section1/item/overview.html'}).
segment('edit', {
templateUrl: 'templates/section1/item/edit.html'}).
up().
segment('prefs', {
templateUrl: 'templates/section1/prefs.html'}).
up().
segment('s2', {
templateUrl: 'templates/section2.html',
controller: MainCtrl});
You should get ui-router for that. I believe it's the only module that lets you do nested views.
source code: https://github.com/angular-ui/ui-router
instructions how to use: https://github.com/angular-ui/ui-router/wiki
Related
We have to design a angular multi-page application. And the pages look something like this:
I planned to design the page in such a way that each section of the page will have a particular angular controller associated to it and a template will be defined which will be added via the ng-include directive. So basically the page 1 (route ==> '/') will have a 4 different sections which will have 4 different controllers.
Now ofcourse this works fine on a single page, but I am unsure how to define the routes here.
1) Should I have nested controllers, so for page 1 we have a page1Controller and all the other controllers will be under this. Will this be a good design?
or
2) Should I have one controller per page which will make the routing easy and have directives defined for each sections of the page?
I think I would recommend just using multiple named views. Each named view can have its own controller:
$stateProvider
.state('home', {
url: '/',
views: {
'': {
templateUrl: 'templates/app.tpl.html',
},
'section1': {
controller: 'Section1Controller as vm',
templateUrl: 'templates/section1.tpl.html'
},
'section2': {
controller: 'Section2Controller as vm',
templateUrl: 'templates/section2.tpl.html'
},
'section3': {
controller: 'Section3Controller as vm',
templateUrl: 'templates/section3.tpl.html'
},
'section4': {
controller: 'Section4Controller as vm',
templateUrl: 'templates/section4.tpl.html'
}
}
})
.state('page2', {
url: '/page2',
views: {
'': {
templateUrl: 'templates/page2.tpl.html',
},
'section1': {
controller: 'Section1Controller as vm',
templateUrl: 'templates/section1.tpl.html'
},
'section2': {
controller: 'Section2Controller as vm',
templateUrl: 'templates/section2.tpl.html'
},
'section3': {
controller: 'Section3Controller as vm',
templateUrl: 'templates/section3.tpl.html'
}
}
})
Then, when you lay out the views, they look something like this:
<div ui-view="section1"></div>
<div ui-view="section2"></div>
<div ui-view="section3"></div>
<div ui-view="section4"></div>
I would use directives to allow multiple controllers, to re-use code between page1 and page 2, and to prepare for the migration to Angular 2.
Your page would look like:
<section1></section1>
<section2></section2>
<section3></section3>
<section4></section4>
And you will have to write a directive per section:
module.directive('section1', function() {
return {
scope: {},
bindToController: {
},
controller: function() { },
controllerAs: 'vm',
template: `
<div>This is section1
</div>
`
}
});
Here is an article to approximate module in Angular 1.x
If you are interested in using TypeScript, here is an tutorial that includes two pages with 2 shared sections using directives as explained above. Look at the section close to the end called 'Sample pages with shared directives.' The tutorial includes a github repository.
In that tutorial, page1 looks like
h1 page1
page1-section1
page1-section2
And, the second page shared the same sections:
h1 page2
page2-section2
page2-section1
The controllers between page1 and page2 are very similar and creates the section tags using the same/shared directives (DigiSection1.Section1Directive):
angular
.module('digiangularjs.page1', [])
.controller('agendaController', Page1Controller)
.directive("page1Section1", [() => new DigiSection1.Section1Directive()])
.directive("page1Section2", [() => new DigiSection2.Section2Directive()])
;
And for the second page, we use the same directives, but
angular
.module('digiangularjs.page2', [])
.controller('page2Controller', Page2Controller)
.directive("page2Section1", [() => new DigiSection1.Section1Directive()])
.directive("page2Section2", [() => new DigiSection2.Section2Directive()])
;
Going off Mike's answer I would define your route-level templates as single components that are high level layout containers.
.state('page1', {
url: '/page1',
template: '<page1></page1>'
})
.state('page2', {
url: '/page2',
template: '<page2></page2>
});
Then in your <page> components (which just dictate layout of nested directives/components) you could do:
.component('page1', {
template: [
'<section1></section1>',
'<section2></section2>',
'<section3></section3>'
].join('')
});
Also I realize you wrote "multi page applicaton" which would suggest you don't plan on using a router at all. If that is the case your backend will have to take care of the dynamic layout generation, which is a totally different question.
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
For some reason $state.current.name is always blank when I try to access it from a directive controller. Does the directive load before state evaluation? If so, is there a work around for this? I need to show the correct navigation based on the state in a SPA
For example in my view, I have: <navigation></navigation>
My directive:
angular.module('app')
.directive('navigation', function($state){
return {
restrict: 'E',
controller: function() {
alert($state.current.name);
}
}
});
My routes:
angular.module('app')
.config(function ($stateProvider, $urlRouterProvider, $locationProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
.state('home', {
url: '/home',
views: {
"title": {
template: "<title>Home</title>"
},
"body": {
templateUrl: 'app/components/home/homeView.html',
},
"navigation" : {
templateUrl: 'app/shared/navigation/homeNavBarView.html'
}
}
})
});
The way i have it set up is that i create the module separately, then i setup routing in a separate file, and the directive is also in a separate file. Then they are loaded in an index file in order. Not sure if this has anything to do with it.
What am I doing wrong?
Does your controller also have to have $state as a parameter?
Just a guess as everything looks solid to me:
controller: function($state) {
alert($state.current.name);
}
Use $state.$current object instead of $state.current
I have simple table page (with controller) and init method like ng-controller="messageGridCtrl" ng-init="init()" and create page with different controller.
Create page has back link like Back to list, when I click route changed and init method invoked, but request don't work (don't recieve to server).
If I just reload (via f5) all works fine.
I'm new to angularjs.
From the angular-route-segment documentation,
$routeSegmentProvider.
when('/section1', 's1.home').
when('/section1/prefs', 's1.prefs').
when('/section1/:id', 's1.itemInfo.overview').
when('/section1/:id/edit', 's1.itemInfo.edit').
when('/section2', 's2').
segment('s1', {
templateUrl: 'templates/section1.html',
controller: MainCtrl}).
within().
segment('home', {
templateUrl: 'templates/section1/home.html'}).
segment('itemInfo', {
templateUrl: 'templates/section1/item.html',
controller: Section1ItemCtrl,
dependencies: ['id']}).
within().
segment('overview', {
templateUrl: 'templates/section1/item/overview.html'}).
segment('edit', {
templateUrl: 'templates/section1/item/edit.html'}).
up().
segment('prefs', {
templateUrl: 'templates/section1/prefs.html'}).
up().
segment('s2', {
templateUrl: 'templates/section2.html',
controller: MainCtrl});
It might help you
http://scotch.io/tutorials/javascript/angularjs-multi-step-form-using-ui-router
I have a problem trying to load a JavaScript method in nested views using ui-router. I have this code:
$stateProvider
.state('/', {
url: '/',
controller: 'MainCtrl',
views: {
'': { templateUrl:'partials/home.html'},
'navbar#': {
templateUrl: 'includes/navbar.html'
},
'sidebar#': {
templateUrl: 'includes/sidebar.html'
}
}
})
and in the index.php
<div ui-view="navbar"></div>
<div ui-view="sidebar"></div>
the content is loaded but some methods do not work. For example this:
$(function() {
$('#side-menu').metisMenu();
});
If I put the sidebar and navbar code directly in the index.php, the JavaScript method works. However, if the code is in nested view, it doesn't work.
ps: I'm using this template http://startbootstrap.com/templates/sb-admin-2/