I have a application which uses angularjs and I use ui-rourer for routing
I need to have multiple controller for a single page, Is it possible ?
This is my route.js code
.state(ROUTE.appGroup, {
abstract: true,
views: {
'content#': {
templateUrl: GLOBAL.viewPath + '/index.html',
controller: 'appCtrl'
}
}
})
I need something like
.state(ROUTE.appGroup, {
abstract: true,
views: {
'content#': {
templateUrl: GLOBAL.viewPath + '/index.html',
controller: 'appCtrl,mainCtrl'
}
}
})
Can anyone help?
Each view, has its controller.
And while state can have more views (differently named) -
each view can have exactly one controller (default is created if none is passed)
Either create more views (to get more controllers into play)
or just move that functionality to services
Related
I have a working app though I am changing the architecture, cutting views down into smaller, more manageable documents. I currently have a state with a child state.
.state('patents', {
url: '/patents',
templateUrl: 'p3sweb/app/components/patents/views/list-patents.htm',
controller: 'listPatentsCtrl',
controllerAs: '$ctrl',
})
.state('patents.patent', {
url: '/{patentId}/:patentHref',
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
})
When I click on a table row in state patents, up pops patents.patent view below it.
I have now changed it so the child patents.patent state has multiple views like so:
.state('patents.patent', {
url: '/{patentId}/:patentHref',
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm',
views: {
'#': {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
},
'patentinfo#patents.patent': {
templateUrl: 'p3sweb/app/components/patents/views/ui-views/patent-info.htm',
controller: 'patentInfoCtrl',
controllerAs: '$ctrl'
},
'patentcostanalysis#patents.patent': {
templateUrl: 'p3sweb/app/components/patents/views/ui-views/patent-costanalysis.htm',
controller: 'patentCostAnalysisCtrl',
controllerAs: '$ctrl'
},
'patentrenewals#patents.patent': {
templateUrl: 'p3sweb/app/components/patents/views/ui-views/patent-renewals.htm',
controller: 'patentRenewalsCtrl',
controllerAs: '$ctrl'
}
})
When I now click on the row in state patents, the patents.patent view replaces the parent view. So instead of displaying below it, it's the only view displayed.
Question
How do I resolve the issue that has occurred now I have included multiple views in patents.patent state?
So it turns out, after reading ui-router wiki, using # creates an absolute path, and I wasn't targeting the view in the parent state patents.
So instead of
views: {
'#': {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
}
It should of been
views: {
'#patents': {
templateUrl: 'p3sweb/app/components/patents/views/patent-item.htm'
}
I am attempting to set up nested views loading in the parent views via state children but I'm not sure if I'm going about this the correct way.
So far, I have:
$stateProvider
.state('splash', {
url: '/splash',
templateUrl: 'system/templates/splash.html',
controller: ""
}).state('home', {
url: '/',
templateUrl: 'system/templates/home.html',
controller: ""
}).state('user', {
url: '/user/:user?',
templateUrl: 'system/templates/user.html',
controller: "userController"
}).state('user.data', {
views: {
"#vdata" : {
templateUrl: 'system/templates/user.html',
controller: "userController"
}
}
})
The "user" parent state recieves :user? the correct way, however when I try to navigate via $state.transitionTo();, I get the response of
Param values not valid for state 'user.data'. I have an unnamed view with the pattern
<div ui-view></div>
set as the parent. Then nested in the user template, I have a ui-view called "vdata". According to the documentation, if I target #vdata, the pages requested should be loading there.
How can I get the nested view to inherit the parameter from the parent view?
Use resolve and inject user on controller. The resolved references are shared betwen parent child states.
$stateProvider
.state('splash', {
url: '/splash',
templateUrl: 'system/templates/splash.html',
controller: ""
}).state('home', {
url: '/',
templateUrl: 'system/templates/home.html',
controller: ""
}).state('user', {
url: '/user/:user?',
templateUrl: 'system/templates/user.html',
controller: "userController",
resolve:{
user: function($stateparams){
return $stateParms.user;
}
}
....
On usercontroller inject user
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
I am working on a MEAN application and I don't know how can I make my ui-router work as expected.
I have an index.html template where i load all my javascript and css that my application needs to work like angular, jquery, angular-ui-x, bootstrap and inside the index's body i have set an ui-view.
The first state I'm using is login, that uses all index's body ui-view. When users is logged in succesfully, it redirects to a home.html page (state: home) which also is using all index's body. Home has a sidebar a header and a content. Inside home's content i'm placing a nested ui-view.
I want every content that comes next inside home's ui-view. And if it's possible i want to make home abstract so i dont have to do home.state1, etc.
To clarify things i have draw an image (I know, my mspaint level is impressive).
And here are my states:
myApp.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise("login");
$stateProvider
.state('login', {
url: '/login',
templateUrl: '../views/login.html',
resolve: {
deps: ['$ocLazyLoad', function ($ocLazyLoad) {
return $ocLazyLoad.load([{
name: 'myApp',
files: [
'js/controllers/LoginCtrl.js',
'css/login.css'
]
}]);
}]
}
})
.state('home', {
url: '/home',
templateUrl: '../views/home.html',
resolve: {
deps: ['$ocLazyLoad', function ($ocLazyLoad) {
return $ocLazyLoad.load([{
name: 'myApp',
files: [
'js/controllers/homeCtrl.js',
'css/template.css'
]
}]);
}]
}
})
});
Here is an exemple of multiple states with some statics parts (menus etc...)
See it working in this plunker
Here are the states definitions :
app.config(function($stateProvider, $urlRouterProvider){
$urlRouterProvider.otherwise('/login');
$stateProvider
.state('login', {
url: '/login',
templateUrl: 'login.html',
controller: 'LoginCtrl'
})
//This is not a real view so we put it abstract
//This will manage the menus
.state('app', {
abstract: true,
templateUrl: 'app.html',
controller: 'AppCtrl'
})
.state('app.home', {
url: '/home',
templateUrl: 'home.html',
controller: 'HomeCtrl'
})
.state('app.greetings', {
url: '/greetings',
templateUrl: 'greetings.html',
controller: 'GreetCtrl'
})
});
Hope it helped, if you have any other question feel free to ask.
EDIT : I personally prefer to call the abstract state "app" cause it symbolize the application view.