0

This is not a duplicate answered by this post nor the (correct) explanation of what the asterisk operator does here. It builds on base of those, though.

The bottom line is that that *ngBeep is an convenient way, syntactic sure, brief expression for [ngBeep]. However, in my code, I've used the following expressions. They do precisely the same thing (as far I can tell) and behave as expected.

<div *ngFor="let item of [1,2,3]">
  #{{item}}
  <ng-container *ngTemplateOutlet="content"></ng-container>
  <ng-container [ngTemplateOutlet]="content"></ng-container>
</div>

Well... technically speaking, the former is shorter than the latter. However, it seems silly to introduce a whole new operator to eliminate a single character. Of course, for other directives, the saved characters/lines may be quite more than the above specific example.

Are those two container lines precisely equivalent (in this, pathological case)? If not, how do they differ (under the hood)?

2 Answers 2

3

Are those 2 lines in the question equivalent?

Yes.

However, star-syntax-sugar is slightly more than that. Firstly, it wraps its contents in the ng-template (because you need to render this template on some condition or, possibly, multiple times, depending on the directive). It means the following code.

<span *ngIf="show">text</span>
// equivalent
<ng-template [ngIf]="show"><span>text</span></ng-template>

Secondly, it adds a prefix for the fields passed, as below.

<ng-container *ngTemplateOutlet="content; context: {var1: 123}">
</ng-container>
// ...and its equivalent
<ng-container [ngTemplateOutlet]="content" 
              [ngTemplateOutletContext]="{var1: 123}">
</ng-container>

Then, it references the data that the directive itself provides in the context, which is more convenient, like so.

<li *ngFor="let item of items; index as i; first as isFirst; trackBy: trackByFn">...</li>
// equivalent
<ng-template ngFor let-item [ngForOf]="items" 
             let-i="index" let-isFirst="first"
             [ngForTrackBy]="trackByFn">
  <li>...</li>
</ng-template>
3
  • Great answer! I took liberty to polish it linguistically - I hope you don't mind. The technical aspect of it is perfect and I clearly understand how my recent ignorance was leading me to confusion. Thanks, mate. Apr 13 at 11:40
  • No... they are not equivalent. You explained that yourself. I was about to downvote just after reading "Yes". But then... I read it all, you're right in your whole answer except that "Yes" part which I find confusing for TL;DR's. The correct equivalencies are the ones you pointed at your examples. Please just fix that first part of your answer, Currently your answer says "yes they are equivalent, however... no, the correct equivalency are all of this..."
    – luiscla27
    Apr 19 at 0:49
  • I would say <ng-container *ngTemplateOutlet" is also a sugar for <ng-template [ngTemplateOutlet]><ng-container>...
    – yurzui
    2 days ago
2

As you can see in the source code, using *ngTemplateOutlet and [ngTemplateOutlet] does not differ since you are using the very same class.
Looking at the class you can see this property:

@Input() public ngTemplateOutletContext: C | null = null;

This translates in the following snippets being almost equivalent:

<ng-container *ngTemplateOutlet="content; context: myContextObj">
</ng-container>
<ng-container [ngTemplateOutlet]="content" 
              [ngTemplateOutletContext]="myContextObj">
</ng-container>

In fact, using the * shorthand you can specify the inputs if the Directive follwed by a semicolon. This is true for every structural directive: they can be used referring to their selector or can be used with the structural directive * shorthand.

What happens under the hood to make the former snippets different?
If you take a look at the docs I linked you will see that while using the * shorthand, Angular will wrap your element in a ng-template and will apply the directive with the selector to it:
From the docs, these two templates are equivalent:

<div class="name" *ngIf="hero">{{hero.name}}</div>
<ng-template [ngIf]="hero">
  <div class="name">{{hero.name}}</div>
</ng-template>

You see that with these powerful tools complexity can escalate quickly, so Angular does not allow 2 structural directives on the same element because it would be impossible to priorly know which directive should have the priority.

This is maybe the only difference between the two approaches that can affect developer experience: if you want to use ngTemplateOutlet and another structural directive, you have 2 possibilities:

  1. Wrap the element in a ng-container and use the structural directive in 2 different elements
  2. Use only one * shorthand
// Using 2 "*" shorthand in the same element: the code won't compile
<ng-container *ngTemplateOutlet="content" *ngIf="true">
</ng-container> 

// Approach 1, the code will compile
<ng-container *ngIf="true">
  <ng-container *ngTemplateOutlet="content">
  </ng-container>
</ng-container>

// Approach 2, the code will compile
<ng-container [ngTemplateOutlet]="content" *ngIf="true">
</ng-container>
7
  • Could you elaborate a bit more on the different capacities regarding using structural directives? Apr 13 at 11:38
  • Sure! I understood the question was not reguarding the use of the * operator, I edited the answer now Apr 13 at 12:23
  • Yes, you got the question correctly first time too. I just wanted some elaboration to confirm that I understood it fully as well as the "future generations" seeing the answer, who may be even more desperately confused than I was. I already accepted the other reply as an answer but for the great effort, I'll +1 you and throw in a bounty, too. You deserve it. Apr 13 at 12:32
  • Correction on the bounty part. It seems I can't. There's no button to start the county (not even telling me it's eligible for it in a period of time). Maybe it's because I already have one active...? Not sure. Apr 13 at 12:34
  • Thank you! I think we have to wait for a couple of days. "A bounty can be started on a question two days after the question was asked.". If you think this answer deserve visibility I'd ask you to upvote it if not mark it as the accepted answer so it doesn't lose visibility for future readers. Apr 13 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.