Repository: angular
Issue: Support cold event streams in templates
Labels: feature,area: core,core: event listeners,cross-cutting: observables,feature: under consideration

# Requirements
* [R1] Observables must be cold (ie if there is no subscription then there should be no listeners.)
USE CASE: drag and drop. No need to listen on mousemove if drag has not been initiated.
* [R2] It must be possible to execute an expression which computes the action which will be next-ed into the observable.
  - USE CASE: ngFor shows a list of todos with a remove button. Clicking the remove should notify the stream not with the DOM event, but with the item to be removed.
* [R3] It must be possible to set up observable recipes to run inside/outside of angular zone.
  - USE CASE: 
    - drag and drop. Don't run CD on mousemove. 
    - Throttle; debounce; etc..: Only run CD on subscription which pass throttle, debounce; etc.
* [R4] It would be strongly preferable if there was something in the template which would indicate that an observable is listening at a given location. 
  - USE CASE: it should be easy for the developer/tooling to see where in the source code the event will be processed.


# Design

* Component will annotate fields which will represent Observable Streams which will be created by the Template's ViewFactory. [R4] (This will also determine the parameterization for the Observables. (ie `Observable<MyType>)`)
  - The Framework will set those fields right after constructing the object. We need a new hook (`ngOnCreate`) which would be called right after setting the fields but before running first change detection (`ngOnChanges`, `ngOnInit`).
* Create new syntax which will describe [R4]:
  - Which events should the template listen on [R4].
  - How should the action be computed [R2].
  - Which stream should receive the action
*Split Angular Zone into `NgErrorZone` for error handling and `NgChangeDetectionZone` for CD. [R3]
  - Provide convenience method running code in `NgErrorZone` and `NgChangeDetectionZone`. [R3]

```ts
@Component({
  template: `
    <ul>
      <li *ngFor="let user of users; let i = index">
        {{user.name}}
        <button (*click|remove)="{item: user, index: i}">X</button>
      <li>
    <ul>
`
})
class MyComponent implements OnCreate{
  users: User[] = ...;


  // Specify that this will have property injection.
  @Inject()
  remove: Observable<{item: User, index: number}>;


  actions: Observable<Action>;


  ngOnCreate() {
    // An example of building up a recipe.
    // Notice that we are making sure that Rx operators have no CD.
    this.actions = noChangeDetection(() => remove.map(() => ...));
  }
}
```

* ViewFactory creates an instance of Observable which then is property injected into component
  - Observable names and types (Type parameters) are declared in the component
  - `@Inject()` identifies that the observable has to be generated in the `ViewContainer`.
  - Need a `ngOnCreate()` hook to create recipes.
* Need `noChangeDetection()` method for  going in and out of CD. Separate Design Doc TBD.
* `(*click|remove)="{item: user, index: i}"` Placeholder syntax, see discussion later. This is used to generate cold event registration for DOM events. The expression is used to compute the value which will be next ed into the observable.
  - Notice that even though there are zero or more instance of places where we listen into DOM events, there is always only one observable instance given that name.

# Syntax Discussion

NOTE: The above syntax is used only as a placeholder

The Syntax Requirements:
* The syntax needs to encode three items:
  - `event`: The DOM event
  - `stream`: The destination stream
  - `actionExp`: The action object
* Given that we need to encode three things and that `key="value"` only takes two by default we have to figure out how to encode three things into two. The choices are:
  - `event+stream="actionExp"`: [favorite]
    - This format combines event and stream on the LHS. 
    - Both event and stream are just symbols (ie foo) not complex expressions (ie `{name: foo + 2}`) and so they can be on the LHS. 
    - Event is already on LHS in `(event)="stmt"` so it should stay there.
    - There is already a precedence for compound LHS in `style.width.px="123"`.
    - Example: `(*click|remove)="actionExp"`. 
      - The `*` is preferred (not necessary) as it hints that it is cold (not always listening)
      - The `(...)` should be retained to be consistent with normal event listeners
  - `event="stream+actionExp"`: [probably not]
    - Micro Syntax has precedence for combining multiple formats on the RHS (but it requires special symbol on the LHS to activate it.) 
    - Microsyntax is shorthand for an expanded canonical form. Here there would be no canonical form. 
    - Example: `(*click)="actionExp into remove"`
      - The `*` is required as it hints that it is cold (not always listening) and that it is different from normal listener.
      - The `(...)` should be retained to be consistent with normal event listeners
* `stream-action="actionExp" stream-event="event"`: [strongly against]
  - Require two key-value pairs.
  - This format is just very wordy and cumbersome. 
  - Puts event on the RHS whereas it is on LHS in `(event)="stmt"`.