Issue 1:
[ ] bug report

[x] feature request

[ ] support request

What is the motivation / use case for changing the behavior?

Angular is built with Observables and we have async pipe which is great. But it makes a template a little bit noisy. There is standard way to call Observable type variables with $ in the end of name, so we can simplify a template by omitting the pipe and making variables with $ recognizable as "asynced" by default.

<my-copmonent [data]="dataStream$ | async"></my-copmonent>
<my-copmonent *ngIf="!(dataStream$ | async)"></my-copmonent>
// into
<my-copmonent [data]="dataStream$"></my-copmonent>
<my-copmonent *ngIf="!dataStream$"></my-copmonent>

I guess there should be some configuration config option to not to brake old style,

or we can look in a template if it has async pipe.

Issue 2:
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]

@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".