0

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 :

  • component are controller + template + bindings. Controller can be omitted.
  • states are url + template + controller or url + component. Controller can be omitted.

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"

Olivvv
  • 1,140
  • 1
  • 13
  • 37

3 Answers3

2

Yes, it is possible. Your ui-router config would look something like this: (Multiple states 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!

tanmay
  • 7,761
  • 2
  • 19
  • 38
  • thanks but I asked this specifically about angular components. Components define a template too, so I am confused between ui-router template a component template. – Olivvv Mar 29 '17 at 08:50
  • mmmh I suppose this is a very relevant question apparently I have "angular": "^1.5.2", "angular-ui-router": "^0.3.1" which trnalsates into 0.3.2 installed. I'll try ui-router version 1.0 alpha. now. – Olivvv Mar 29 '17 at 09:04
  • actually I am confused now. There is angular-ui-router && ui-router. I guess one is a fork of the other into angular. if you have any recommendation I'll take it. Whatever is best for use with angular components. – Olivvv Mar 29 '17 at 09:14
  • @Olivvv `angular-ui-router` – tanmay Mar 29 '17 at 09:16
  • I'd recommend using components instead of using controllers and I disagree with your quote by Eric Elliot in this instance. Purposefully using deprecated concepts because 'It's easier this way and it's less work' is also known as *laziness*. – Dan Mar 29 '17 at 10:03
  • @DanPantry I sort of agree with you but since all components are using same controller but different templates, I was leaning towards *this* approach – tanmay Mar 29 '17 at 10:10
  • @DanPantry would you share your suggested code/architecture then ? – Olivvv Mar 29 '17 at 10:11
  • @tanmay I am currently updating my knowledge to es6/ng1.5, so every step is more painful than with a well know older stack. But here, I am confident that components have been thought with crud in mind. There must be a right way, I just don't see it clearly as for now, but I want to find out. Also, I dont really have choice to not use components, it is a company guideline. They have the vision, I implement... – Olivvv Mar 29 '17 at 10:12
0

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

Jayant Patil
  • 1,537
  • 2
  • 11
  • 18
0
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.

Dan
  • 10,282
  • 2
  • 37
  • 64
  • I am studying your answer. By "newer versions" you mean "1.0.0-rc.1", right ? https://github.com/angular-ui/ui-router/releases – Olivvv Mar 29 '17 at 14:19
  • Do I understand right that you recommend to have seperate "read", "create", "update" components ? – Olivvv Mar 29 '17 at 15:07
  • I'd recommend you have a component for the display of each route. You could have a single component with all of the shared behaviour if you wanted, although the more you describe this, the more it sounds like you want a service that handles the CRUD operations. – Dan Mar 29 '17 at 16:02