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

Custom component decorators #6643

Closed
jeffbcross opened this issue Jan 22, 2016 · 6 comments
Closed

Custom component decorators #6643

jeffbcross opened this issue Jan 22, 2016 · 6 comments
Assignees
Labels
area: core Issues related to the framework runtime feature Issue that requests a new feature state: Needs Design
Milestone

Comments

@jeffbcross
Copy link
Contributor

Goals

  • Encourage third-party libraries to be useful with Angular components in statically-analyzable ways (i.e. for third-party intelligent CLI tools for refactoring, analysis, etc)
  • Allow decorators to be powerful without having direct side effects on component classes
  • Allow decorators to be able to use providers from a component's injector

Example Use Cases

  • @FirebaseList property decorator
  • @ViewEventObservable property decorator

@FirebaseList Property Decorator

@Component(...)
export class MyComponent {
  @FirebaseList({
    path: 'https://some-firebase.firebaseio.com/todos'
  }) todos:Observable<Todo>;
}

This example would automatically create an Observable from a list of Todo objects from a Firebase.

I've prototyped a @FirebaseList decorator for the new AngularFire library (issue), but it has some downsides.

@FirebaseList Downsides

  1. The decorator doesn't have access to an injector to get a hold of the DEFAULT_FIREBASE provider which gives the app's default Firebase url
  2. The inner decorator function has a side effect of creating an Observable and attaching it to the specified property of the component instance.

I would like an API where I can tell Angular about my decorator, what dependencies it requires, and provide lifecycle callbacks so my library can do work at the appropriate time.

@ViewEventObservable Property Decorator

import {Event} from 'angular2/core';
@Component(...)
class MyComponent {
  @ViewEventObservable({
    selector: 'input[type=checkbox]'
    event: 'change'
  }) todoToggles:Observable<any>
}

We'd like to provide some helpers to create observables from outputs and events of elements within a component's view, without requiring users to write imperative code and inject native elements into component code. If creating this decorator outside of Angular right now is even possible, it would require hacking into private Angular APIs or doing expensive DOM analysis to find the actual view for a component.

I've started thinking about a design for this, but wanted to open for discussion.

@jeffbcross
Copy link
Contributor Author

@jeffbcross
Copy link
Contributor Author

I talked with @tbosch in length about this. We ended up at two conclusions. The 2nd use case (@ViewEventObservable) just needs to be in core, because it would be difficult to design template pre-compilation in such a way that would support external decorators that access a component's DOM. The FirebaseList problem could best be solved with injectable property support from Angular in the core. This way, all that needs to be known about the injection can be known statically, and a decorator is not necessary. So the remaining discussion is: should we support Injectable Properties in Angular?

@Component({
  providers: [FirebaseList({
    path: '/todos',
    query: [['limitToFirst', 10]]
  })],
  template: `
    <ul>
      <li *ngFor="#todo of todos | async">
        {{todo}}
      </li>
    </ul>
  `
})
class MyComponent {
  // FirebaseList would return a Provider that would depend on DEFAULT_FIREBASE
  @InjectProp(FirebaseList) todos:Observable<Todo>;
}

In today's Angular, I could go ahead and use @Inject in my constructor and use public keyword to set value to the instance. But this DI-based solution is sub-par because it requires first creating a provider, then decorating a property or parameter. If I want to have multiple instances of a provider, I'd have to allow specifying some arbitrary token to use:

@Component({
  template: '<h1>Hi</h1>',
  inputs:[],
  providers: [
    FirebaseList({
      token: 'posts',
      path: '/posts'
    }),
    FirebaseList({
      token: 'todos',
      path: '/todos'
    }),
    provide(DEFAULT_FIREBASE, {
      useValue: 'ws://test.firebaseio.com'
    })
  ]
})
class MyComponent {
  constructor(@Inject('posts') public posts:Observable<any>, @Inject('todos') public todos:Observable<any>) {
  }
}

@timruffles
Copy link
Contributor

Would also be nice for things like defaulting to OnPush across a codebase. This is what the ng 2 advanced boilerplate is doing

@mhevery mhevery added area: core Issues related to the framework runtime and removed comp: core labels Sep 7, 2016
@vicb vicb added the feature Issue that requests a new feature label Oct 7, 2016
@ngbot ngbot bot added this to the Backlog milestone Jan 23, 2018
@splincode
Copy link
Contributor

@jeffbcross @mhevery Is the issue relevant?

I think this does not apply to angular
decorators can be written separately from the framework

@mhevery
Copy link
Contributor

mhevery commented Aug 7, 2018

obsolete

@mhevery mhevery closed this as completed Aug 7, 2018
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: core Issues related to the framework runtime feature Issue that requests a new feature state: Needs Design
Projects
None yet
Development

No branches or pull requests

6 participants