-
Notifications
You must be signed in to change notification settings - Fork 25.5k
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
feat: ngIf now supports else; saves condition to local var #13297
Conversation
* | ||
* # Showing alternative template using `else` | ||
* | ||
* At times it is important to display alternative template when the expression is falsy and inline |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is "At times it is important" really necessary in API docs ?
May use the then
/ else
template terminology introduced earlier ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewritten
* | ||
* If the expression assigned to `ngIf` evaluates to a falsy value then the element | ||
* is removed from the DOM, otherwise a clone of the element is reinserted into the DOM. | ||
* # Using non-inlined `then` template |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
non-inlined -> reference ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think non-inlined makes more sense here.
* | ||
* ### Example ([live demo](http://plnkr.co/edit/fe0kgemFBtmQOY31b4tw?p=preview)): | ||
* Usually the `then` template is the inlined template of the `ngIf`, but it can be changed using | ||
* a binding (just like `else`.) Because it is a binding, the `then` template can change over time. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because they are bindings, templates reference can be changed over time ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewritten
* # Storing conditional result in a variable | ||
* | ||
* A common patter is that we need to show a set of properties from a same object, but if the | ||
* object is undefined, the we have to use the safe-traversal-operator to guard against |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
, then (missing n)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
* ``` | ||
* | ||
* There are several inefficiencies in the above example. | ||
* - We create multiple subscriptions on the `userStream`, one for each `async` pipe. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
multiple -> 2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewritten
* - We create multiple subscriptions on the `userStream`, one for each `async` pipe. | ||
* - We have to place the `async` pipe in parenthesis. | ||
* - We have to use the safe-traversal-operator `.?` to access properties. | ||
* - We can not display an alternative screen while waiting for the data to arrive asynchronously. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move this one up (order by importance)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reordered
* - We have to use the safe-traversal-operator `.?` to access properties. | ||
* - We can not display an alternative screen while waiting for the data to arrive asynchronously. | ||
* | ||
* The example below shows a better way to achieve a better result. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The better example ... :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewritten
* | ||
* Notice that: | ||
* - We use only one `async` pipe and hence only one subscription gets created. | ||
* - `ngIf` stores the result of the `userStream|async` in the `$implicit` location. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to mention implicit here (add a note below) or at all ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rewritten
* ### Syntax | ||
* | ||
* Simple form: | ||
* - `<div *ngIf="condition">...</div>` | ||
* - `<div template="ngIf condition">...</div>` | ||
* - `<template [ngIf]="condition"><div>...</div></template>` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we had decided to document this <ng-container *ngIf>
.
Can you update as part of this PR ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out that we can't do that because <ng-container #foo>
is not supported. We need to fix that first nad than come back and change this.
* - `<div *ngIf="condition">...</div>` | ||
* - `<div template="ngIf condition">...</div>` | ||
* - `<template [ngIf]="condition"><div>...</div></template>` | ||
* | ||
* Form with an else block: | ||
* - `<div *ngIf="condition; else elseBlock">...</div><template #elseBlock>...</template>` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove the leadin - ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
split on 2 (3 below) lines ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
this._hasView = false; | ||
this._viewContainer.clear(); | ||
this._context.$implicit = condition; | ||
this._updateView(condition); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this._updateView();
remove useless param and use the context
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
fixture = createTestComponent(template); | ||
|
||
fixture.detectChanges(); | ||
expect(getDOM().getText(fixture.nativeElement)).toEqual('TRUE'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.toHaveText()
doesn't work here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed (copy paste from existing test)
expect(getDOM().getText(fixture.nativeElement)).toEqual('FALSE'); | ||
})); | ||
|
||
it('should support else', async(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
then + else ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
@@ -685,7 +685,7 @@ class TemplateParseVisitor implements html.Visitor { | |||
} | |||
elementProps.forEach(prop => { | |||
this._reportError( | |||
`Property binding ${prop.name} not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "directives" section.`, | |||
`Property binding ${prop.name} not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations".`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or imported ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure I understand, what you mean by imported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think he means: Property binding ${prop.name} not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the "@NgModule.declarations" or imported by the @NgModule
@@ -704,7 +704,7 @@ class TemplateParseVisitor implements html.Visitor { | |||
events.forEach(event => { | |||
if (isPresent(event.target) || !allDirectiveEvents.has(event.name)) { | |||
this._reportError( | |||
`Event binding ${event.fullName} not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "directives" section.`, | |||
`Event binding ${event.fullName} not emitted by any directive on an embedded template. Make sure that the event name is spelled correctly and all directives are listed in the "@NgModule.declarations".`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
# Running the examples | ||
|
||
``` | ||
./build.sh # run only when framework code changes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you the command above the line and chg to # execute the following command only ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
``` | ||
|
||
NOTE: sometimes the http server does not exits properly and it retans the `8001` port. | ||
in Such a case you can use `lsof -i:8001` to see which process it is and then use `kill` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In such
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
very sweet ! LGTM after comments are addressed. please aslo scope the commit messages by cmp. |
@vicb please take another look. |
7f3b034
to
ca9c028
Compare
still failing CI |
NgIf syntax has been extended to support else clause to display template when the condition is false. In addition the condition value can now be stored in local variable, for later reuse. This is especially useful when used with the `async` pipe. Example: ``` <div *ngIf="userObservable | async; else loading; let user"> Hello {{user.last}}, {{user.first}}! </div> <template #loading>Waiting...</template> ``` Closes angular#13061
finally green, and all comments addressed. |
./modules/@angular/examples/test.sh | ||
``` | ||
|
||
NOTE: sometimes the http server does not exits properly and it retans the `8001` port. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does not exits -> does not exit
it retans -> it retains
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@souldreamer I'll fix when merging the PR. thanks
How do I know which version of Angular will have this? Is this documented anywhere? Thanks |
@DzmitryShylovich, thanks, just found that too. I assume that means not going 2.x? Pity... |
@OndraZizka nope. this feature is 4.x only |
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
NgIf syntax has been extended to support else clause to display template
when the condition is false. In addition the condition value can now
be stored in local variable, for later reuse. This is especially useful
when used with the
async
pipe.Example:
Closes #13061