Reputation: 1200
In a component I would like to associate templates to CRUD actions, but use a single controller that handles data for all all of them. Does this make sense with angular components, or should I use several components ? How would the ui-router state configuration look like ?
EDIT: Components have templates, and ui-router states too. I am confused about the articulation of those 2 concepts.
EDIT 2: trying to clarify my understanding so far :
So it seems that components are taking away some of the responsabilities that use to belong to ui-router.
My goal here:
- url1 --> controller foo + template x;
- url2 --> controller foo + template y;
- url3 --> controller foo + template z;
should I do :
components:
component x --> controller foo + template x;
component y --> controller foo + template y;
component z --> controller foo + template z;
and then routing:
url 1 --> component x
url 2 --> component y
url 3 --> component z
?
EDIT 3: quote from https://docs.angularjs.org/guide/component :
"In a component-based application, every view is a component"
quote from https://ui-router.github.io/guide/ng1/route-to-component :
"The component model enforces separation of concerns and encapsulation by using an isolate scope. Data from parent scopes can no longer be directly accessed. Instead, it needs to be explicitly wired in"
Upvotes: 0
Views: 1065
Reputation: 10538
angular.module('', [])
// Route handler touches this
.component('route1', {
template: `<shared-behaviour>
<route-view-1></route-view-1>
</shared-behaviour>`
})
// This is a purely visual component that links actions with the shared behaviour component
.component('routeView1', {
require: {
shared: '^sharedBehaviour'
},
template: '<button ng-click="$ctrl.onClick()></button>',
controller: class RouteView2Ctrl {
onClick() {
this.shared.onSharedClick()
}
}
})
// Contains the shared behaviour that is shared across the multiple routes
.component('sharedBehaviour', {
// Tell Angular to render children passed to this component
transclude: true,
template: '<div ng-transclude></div>',
controller: class SharedBehaviourCtrl {
onSharedClick() {
/// do something
}
}
})
// Newest version of UI-Router
.state('route1', {
component: 'route1'
})
Further to our comments, you could use something like the above. It's pretty verbose, but that's Angular 1.5 for you. Haven't tested that it works, but it's a basic idea of how it might work.
The main take away being that you have the route1
component which only handles linking route stuff (like the url, resolves, etc) and passes that information to its children (of which there aren't any).
routeView1
just renders how the route would work, and uses require
to talk to some parent API that is shared (you could also use one-way bindings for this if you wanted, but with lots of methods this leads to a messy template).
sharedBehaviour
only contains the shared behaviour you want renders any child passed to it.
This is admittedly pretty messy and I would prefer that you instead used one-way bindings for route-view-1
and handled the linking in shared-behaviour
, but this might be quite a bit of repetition. You could use some transclusion magic to solve that, but it's.. not really worth it.
I would really recommend against sharing controllers like other answerers have suggested. In Angular 2 and above, a controller is the component. You share behaviour there by doing something similar to what I have done (or by using one-way bindings with callbacks) and using composition.
BTW as mentioned in my answer, newer versions of UI-Router for Angular 1.5 allow you to specify a component to be rendered rather than a template. See here for more info.
Upvotes: 0
Reputation: 7911
Yes, it is possible. Your ui-router
config would look something like this: (Multiple state
s having same controllers.)
.state('add', {
url: '/add',
templateUrl: 'templates/add.html',
controller: 'contactCtrl'
})
.state('edit', {
url: '/edit',
templateUrl: 'templates/edit.html',
controller: 'contactCtrl'
})
Here's a working example of having multiple states and templates using same controller.
Edit: You don't have to use components
. Why create three different extra components while you can achieve the same thing without them? I would still recommend the approach I mentioned above. Getting the same outcome with lesser code should always be chosen. :)
Quoting Eric Elliot on twitter,
Code is temporary. It exists while it is useful. If code is replaced by better code, good! If code can be deleted, celebrate!
Upvotes: 2
Reputation: 1587
Your state provider will look like this
JS code
$stateProvider
.state('report', {
views: {
'filters': {
templateUrl: 'report-filters.html',
controller: 'ctrl'
},
'tabledata': {
templateUrl: 'report-table.html',
controller: 'ctrl'
},
'graph': {
templateUrl: 'report-graph.html',
controller: 'ctrl'
}
}
})
in single state you can load multiple views
HTML
<body>
<div ui-view="filters"></div>
<div ui-view="tabledata"></div>
<div ui-view="graph"></div>
</body>
refer multiple views
Upvotes: 0