Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Subscribe to component @output? #138

Closed
killersite opened this issue Jun 27, 2017 · 4 comments
Closed

Subscribe to component @output? #138

killersite opened this issue Jun 27, 2017 · 4 comments

Comments

@killersite
Copy link

killersite commented Jun 27, 2017

I really like how in contrast to (what i've understood of) the Angular router, ui-router allows me to exclude the Router dependency from my components. Correct me if I'm wrong -

I.E. the following with ui-router -

resolve: [
    { 
      token: 'person', 
      deps: [Transition, PeopleService],
      resolveFn: (trans, peopleSvc) => peopleSvc.getPerson(trans.params().personId)
    }

which will go right onto the Component @Input() person;.

It seems the equivalent in the Angular router is the following messy code

  constructor(private _route: ActivatedRoute, peopleSvc: PeopleSvc) {
    this.sub = this._route.params.subscribe((params) => peopleSvc.getPerson(params['id']));
  }

or use a Resolve Guard

ngOnInit() {
  this.route.data
    .subscribe((data: { person: Person }) => {
      this.person = data.person;
    });
}

Anyway...

Question: Is it possible to do this for the @output events of my @component? Can we setup the event subscriptions too in the State definition?

I was a big fan of doing that in Angular 1.x with ui-router...

@christopherthielen
Copy link
Member

I'd like to explore this idea, but I'm not sure how it would work. In ui-router/angularjs the parent ui-view could supply a callback which was then passed down to the routed component:

<ui-view on-user-updated="$ctrl.handleUserUpdated(user)"></ui-view>

[https://ui-router.github.io/guide/ng1/route-to-component#routed-parentchild-component-communication](uirouter/angularjs route to component parent/child communication)


For a similar feature in Angular I'd like it to work in a similar way:

<UIView (userupdated)="handleUserUpdated(user)"></UIView>

However, I don't know how you could implement this without declaring the output on the UIView component itself.

Does Anyone have ideas how this could work?

@i23591326
Copy link

In AngularJS i'm using this feature to handle component callback right in state resolve:
angular-ui/ui-router#3111
I found useful to do some logic affecting the entire application in state resolver (like to reload router subtree or fetch more pageable data to component). However, in my particular case this may be a short-sighted architectural solution.

@manisto
Copy link

manisto commented Feb 13, 2018

Hi. I would like to offer whatever help I can to find a solution to this issue. I've spent the last few days looking into how Angular (not AngularJS) works with regards to event handling for components. It doesn't look like you can listen to events without defining them on the component, and you can't have a "catch all" listener.

However, I've also had some issues with the way the event binding was done for UI Router in AngularJS (1.x). Either you had to have a container that listened for the events for a specific set of child states, or you would have far too many listeners on the same view if you have many child states with events. Therefore, I have another solution that I think would go well with the way the resolves work.

Since you're using the ComponentFactoryResolver to instantiate the view components, it would be trivial to make the ui-view directive subscribe to events on the component instance. The listeners could be defined on the state (like the resolves), although I think the listeners would need to be per view instead of state-wide like the resolves. The listener functions could then be injected just like the resolves, something like this:

  ...
  {
    name: "authors.list",
    url: "",
    component: AuthorListComponent,
    listen: [
      {
        token: "editAuthor",
        deps: [AuthorService, EventData],
        listenFn: (service: AuthorService, data: EventData) => {
          let author: Author = data.emittedData;
          // Do something else here
        }
      }
    ],
    resolve: [
      {
        token: "authors",
        deps: [AuthorService],
        resolveFn: resolveAuthorList
      }
    ]
  }
  ...

The listener function would then be invoked each time the view component emits data. Since the router framework would be handling the subscription, it would also know when to unsubscribe the event. I'm not entirely clear on how the emitted data should be passed to the listener function. I have however done a proof of concept to make sure that it is in fact possible to subscribe to dynamically loaded components, as well as binding data to their inputs.

Finally, this would help the decoupling of the components even further, making them even more reusable throughout the system, since they don't need to know where to put data, they simply emit it and become truly stateless.

NINJA EDIT: I was partly inspired by this semi-related comment on another thread: angular/angular#15360 (comment)

@stale
Copy link

stale bot commented Dec 30, 2019

This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs.

This does not mean that the issue is invalid. Valid issues
may be reopened.

Thank you for your contributions.

@stale stale bot added the stale label Dec 30, 2019
@stale stale bot closed this as completed Jan 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants