Angular 4.x NgIf usage, angularngif
NgIf instructions
The ngIf command is used to render then or else template content at a specified position based on the expression value.
- The then template is an inline template associated with the ngIf command by default unless it is bound to different values.
- The else template is null by default unless it is bound with the corresponding value.
NgIf instruction syntax
Simple Form
<! -- Syntax sugar --> <div * ngIf = "condition">... </div> <! -- Use template in Angular 2.x --> <ng-template [ngIf] = "condition"> <div>... </div> </ng-template>
Use else Blocks
<div *ngIf="condition; else elseBlock">...</div><ng-template #elseBlock>...</ng-template>
Use then and else Blocks
<div *ngIf="condition; then thenBlock else elseBlock"></div><ng-template #thenBlock>...</ng-template><ng-template #elseBlock>...</ng-template>
Use the as syntax
<div *ngIf="condition as value; else elseBlock">{{value}}</div><ng-template #elseBlock>...</ng-template>
NgIf usage example
@Component({ selector: 'ng-if-then-else', template: ` <button (click)="show = !show">{{show ? 'hide' : 'show'}}</button> <button (click)="switchPrimary()">Switch Primary</button> show = {{show}} <br> <div *ngIf="show; then thenBlock; else elseBlock">this is ignored</div> <ng-template #primaryBlock>Primary text to show</ng-template> <ng-template #secondaryBlock>Secondary text to show</ng-template> <ng-template #elseBlock>Alternate text while primary text is hidden</ng-template> `})class NgIfThenElse implements OnInit { thenBlock: TemplateRef<any> = null; show: boolean = true; @ViewChild('primaryBlock') primaryBlock: TemplateRef<any> = null; @ViewChild('secondaryBlock') secondaryBlock: TemplateRef<any> = null; switchPrimary() { this.thenBlock = this.thenBlock === this.primaryBlock ? this.secondaryBlock : this.primaryBlock; } ngOnInit() { this.thenBlock = this.primaryBlock; }}
Basic knowledge
TemplateRef
The TemplateRef instance is used to represent the template object. The TemplateRef abstract class is defined as follows:
// angular\packages\core\src\linker\template_ref.tsexport abstract class TemplateRef<C> { abstract get elementRef(): ElementRef; abstract createEmbeddedView(context: C): EmbeddedViewRef<C>;}
ViewContainerRef
The ViewContainerRef instance provides createEmbeddedView()
Method, which receivesTemplateRef
The object is used as a parameter, and the content in the template is inserted into the page as the sibling element of the container (comment element.
NgIfContext
The NgIfContext instance is used to represent the NgIf context.
// angular\packages\common\src\directives\ng_if.tsexport class NgIfContext { public $implicit: any = null; public ngIf: any = null;}
NgIf source code analysis
NgIf instruction Definition
@ Directive ({selector: '[ngIf]' // attribute selector-<ng-template [ngIf] = "condition"> })
NgIf private attributes and constructor
Export class NgIf {// create NgIfContext context private _ context: NgIfContext = new NgIfContext (); // indicates the then template object private _ thenTemplateRef: TemplateRef <NgIfContext> | null = null; // indicates the else template object private _ elseTemplateRef: TemplateRef <NgIfContext> | null = null; // indicates the EmbeddedViewRef view private _ thenViewRef created based on the then template: optional <NgIfContext> | null = null; // indicates the EmbeddedViewRef view private _ elseViewRef: EmbeddedViewRef <NgIfContext> | null = null; constructor (private _ viewContainer: ViewContainerRef, templateRef: TemplateRef <NgIfContext>) {this. _ thenTemplateRef = templateRef; // The default value of the then template is the inline template associated with the ngIf instruction }}
NgIf input attributes
@ Input () set ngIf (condition: any) {this. _ context. $ implicit = this. _ context. ngIf = condition; this. _ updateView (); // update view} @ Input () set ngIfThen (templateRef: TemplateRef <NgIfContext>) {this. _ thenTemplateRef = templateRef; this. _ thenViewRef = null; // clear the previously created view this. _ updateView () ;}@ Input () set ngIfElse (templateRef: TemplateRef <NgIfContext>) {this. _ elseTemplateRef = templateRef; this. _ elseViewRef = null; // clear the previously created view this. _ updateView ();}
_ UpdateView () Private Method
// Update the private _ updateView () {// this. _ context. $ implicit = this. _ context. ngIf = condition // if the value of the condition expression is truthy if (this. _ context. $ implicit) {// if _ thenViewRef is null and _ thenTemplateRef exists, create the _ thenViewRef embedded view if (! This. _ thenViewRef) {this. _ viewContainer. clear (); this. _ elseViewRef = null; if (this. _ thenTemplateRef) {this. _ thenViewRef = this. _ viewContainer. createEmbeddedView (this. _ thenTemplateRef, this. _ context) ;}} else {// The condition expression value is falsy // if _ elseViewRef is null and _ elseTemplateRef exists, the _ elseViewRef embedded view if (! This. _ elseViewRef) {this. _ viewContainer. clear (); this. _ thenViewRef = null; if (this. _ elseTemplateRef) {this. _ elseViewRef = this. _ viewContainer. createEmbeddedView (this. _ elseTemplateRef, this. _ context );}}}}
ngIf
The command source code is relatively simple, and the core is_updateView()
Method. The most important function of this method is to create an embedded view based on the template object. Next, let's analyzeViewContainerRef
Object createEmbeddedView()
Method.
ViewContainerRef-createEmbeddedView ()
Method Signature
// Angular \ packages \ core \ src \ linker \ view_container_ref.tsexport abstract class ViewContainerRef {/*** create Embedded View (Embedded View) based on the TemplateRef object ), insert it to the container based on the value specified by 'index. * If the 'index' value is not specified, the newly created view is inserted as the last view in the container. */Abstract createEmbeddedView <C> (templateRef: TemplateRef <C>, context? : C, index? : Number): EmbeddedViewRef <C> ;}
Method implementation
// Angular \ packages \ core \ src \ view \ refs. tsclass ViewContainerRef _ implements ViewContainerData {//... createEmbeddedView <C> (templateRef: TemplateRef <C>, context? : C, index? : Number): EmbeddedViewRef <C >{// call the TemplateRef object createEmbeddedView () method to create the EmbeddedViewRef object const viewRef = templateRef. createEmbeddedView (context | <any >{}); // insert it to the view container Based on the specified index value. this. insert (viewRef, index); return viewRef ;}// the ViewContainerData interface inherits from the ViewContainerRef abstract class export interface ViewContainerData extends ViewContainerRef {_ embeddedViews: ViewData [];} export interface ViewData {def: viewDefinition; root: RootData; renderer: Renderer2; parentNodeDef: NodeDef | null; parent: ViewData | null; viewContainerParent: ViewData | null; component: any; context: any; nodes: {[key: number]: NodeData}; state: ViewState; oldValues: any []; disposables: DisposableFn [] | null ;}
ObserveViewContainerRef_
Class createEmbeddedView()
Method, we find that this method is called internallyTemplateRef
ObjectcreateEmbeddedView()
To create an embedded view. So let's analyze it again.TemplateRef
ObjectcreateEmbeddedView()
Method.
TemplateRef-createEmbeddedView ()
Method Signature
// angular\packages\core\src\linker\template_ref.tsexport abstract class TemplateRef<C> { abstract createEmbeddedView(context: C): EmbeddedViewRef<C>;}
Method implementation
// angular\packages\core\src\view\refs.tsclass TemplateRef_ extends TemplateRef<any> implements TemplateData { // ... createEmbeddedView(context: any): EmbeddedViewRef<any> { return new ViewRef_(Services.createEmbeddedView( this._parentView, this._def, this._def.element !.template !, context)); }}export interface TemplateData extends TemplateRef<any> { _projectedViews: ViewData[];}
After reading the source code above, there is no doubt that we will continue to analyze it.Services
Object createEmbeddedView()
Method.
Services-createEmbeddedView ()
Services object definition
// angular\packages\core\src\view\types.tsexport const Services: Services = { setCurrentNode: undefined !, createRootView: undefined !, createEmbeddedView: undefined !, createComponentView: undefined !, createNgModuleRef: undefined !, overrideProvider: undefined !, clearProviderOverrides: undefined !, checkAndUpdateView: undefined !, checkNoChangesView: undefined !, destroyView: undefined !, resolveDep: undefined !, createDebugContext: undefined !, handleEvent: undefined !, updateDirectives: undefined !, updateRenderer: undefined !, dirtyParentQueries: undefined !,};
Services object initialization
// angular\packages\core\src\view\services.tsexport function initServicesIfNeeded() { if (initialized) { return; } initialized = true; const services = isDevMode() ? createDebugServices() : createProdServices(); Services.setCurrentNode = services.setCurrentNode; Services.createRootView = services.createRootView; Services.createEmbeddedView = services.createEmbeddedView; Services.createComponentView = services.createComponentView; Services.createNgModuleRef = services.createNgModuleRef; Services.overrideProvider = services.overrideProvider; Services.clearProviderOverrides = services.clearProviderOverrides; Services.checkAndUpdateView = services.checkAndUpdateView; Services.checkNoChangesView = services.checkNoChangesView; Services.destroyView = services.destroyView; Services.resolveDep = resolveDep; Services.createDebugContext = services.createDebugContext; Services.handleEvent = services.handleEvent; Services.updateDirectives = services.updateDirectives; Services.updateRenderer = services.updateRenderer; Services.dirtyParentQueries = dirtyParentQueries;}
IninitServicesIfNeeded()
Method, different Services objects are created based on the current mode. Next let's take a look at it.createProdServices()
Method:
Function createProdServices () {return {setCurrentNode: () =>{}, createRootView: createProdRootView, createEmbeddedView: createEmbeddedView // other methods are omitted}
CreateEmbeddedView () method
// Angular \ packages \ core \ src \ view. tsexport function createEmbeddedView (parent: ViewData, anchorDef: NodeDef, viewDef: ViewDefinition, context? : Any): ViewData {// embedded views are seen as siblings to the anchor, so we need // to get the parent of the anchor and use it as parentIndex. // create the ViewData object const view = createView (parent. root, parent. renderer, parent, anchorDef, viewDef); // initialize the ViewData object-set the value of component and context attributes initView (view, parent. component, context); // create a node in the view, that is, set view. value of the nodes array // const nodes = view. nodes; (...) {...; nodes [I] = nodeData;} createViewNodes (view); return view ;}
At this time, we find that if we analyze all the methods completely, it will involve too much content. Source code analysis ends here. If you are interested, please read the source code yourself (please forgive me ). Next, let's make a summary. createEmbeddedView()
Method call process:
ViewContainerRef_ -> createEmbeddedView() => TemplateRef_ -> createEmbeddedView() => Services -> createEmbeddedView() => Call createEmbeddedView()
The above is all the content of this article. I hope it will be helpful for your learning and support for helping customers.