fearless23
10/14/2017 - 8:15 AM

Ng Template, Outlet Template

<!-- LEt talk about ng-template more
     ng-template defined in component.html has access to all variable from component.ts 
     say courses, apples= 10 etc. defined in component.ts..
     and each ng-template can also define its own set of input variables!
     Actually, each template has associated a context object containing 
     all the template-specific input variables. ===-->
     
<ng-template #hello let-lessonsCounter="estimate">
  <div> Approximately {{lessonsCounter}} lessons ...</div>
</ng-template>

<ng-container *ngTemplateOutlet="hello;context:foo"> </ng-container>

<!--inside Component.ts -->

totalEstimate = 10;
foo = {estimate: this.totalEstimate};

or

foo = { estimate: 10 }

<!-- 
  The input variable is called lessonsCounter,and
  it's defined via a ng-template property using the prefix let-
  
  The variable lessonsCounter is visible inside the ng-template body, but not outside
  
  the content of lessonsCounter variable is determined by the expression that its assigned to the 
  property let-lessonsCounter = "estimate"

  Remember, foo is object passed to ng-container along with hello template reference like this
  " *ngTemplateOutlet="hello; context: foo "  so, foo = { estimate: 10 }
  
  The object foo should contain a property estimate which is expressed in ng-template as
  let-lessonsCounter="estimate" so that is used within template
  
  let-lessonsCounter="estimate" and foo = { estimate: 10} or foo = {estimate: this.number}
  
  if a button runs a function that change number, estimate change, foo changes, 
  ng-container refer to hello ng-template and lessonsCounter change and value on screen change
  
  
<!--=== This will throw an Syntax Error, Multiple Structural Directives ngif and ngfor on one Element ===-->
<div *ngIf="lessons" class="lesson" *ngFor="let lesson of lessons">
  <div class="lesson-detail">{{lesson | json}}</div>
</div>


<!--=== Right but older way without ng-template and we have create an extra div for ngIf ===-->
<div *ngIf="lessons">
  <div class="lesson" *ngFor="let lesson of lessons">
      <div class="lesson-detail">{{lesson | json}}</div>
  </div>
</div>

<!--=== Right and better way and it also avoids having to create that extra div,
        we can instead use ng-container directive: ===-->

<ng-container *ngIf="lessons">
    <div class="lesson" *ngFor="let lesson of lessons">
        <div class="lesson-detail">{{lesson | json}}</div>
    </div>
</ng-container>


<!-- === Ng-container directive provides us with an element
that we can attach a structural directive to a section of the page,
without having to create an extra element just for that.
There is another major use case for the ng-container directive: 
it can also provide a placeholder for injecting a template
dynamically into the page. ===-->

<!--=== Dynamic Template Creation with the ngTemplateOutlet directive ===-->
<!--=== Being able to create template references and point them to other
        directives such as ngIf is just the beginning. ===-->

<!--=== We can also take the template itself and instantiate it anywhere
        on the page, using the ngTemplateOutlet directive: ===-->


<ng-container *ngTemplateOutlet="loading"></ng-container>

<!--=== Here loading is reference to ng-template with #loading ===-->
<!-- ng-template Renders Nothing unless called -->
<ng-template>
  <button class="tab-button" 
          (click)="login()">{{loginText}}</button>
  <button class="tab-button" 
          (click)="signUp()">{{signUpText}}</button>
</ng-template>


<!-- This Renders because ng-template called -->
<div class="lessons-list" *ngIf="lessons else loading">
  ... 
</div>

<ng-template #loading>
    <div>Loading...</div>
</ng-template>