NgIf command function
The ngIf directive is used to render the contents of the then or else template at a specified location based on the value of the expression.
- Then templates are the inline templates associated with the ngIf directive by default unless bound to a different value.
- The else template defaults to null unless the corresponding value is bound.
NgIf instruction syntax
Simple form
<!--Syntactic sugar--> <div *ngIf="condition">...</div> <!--Angular Used intemplate--> <ng-template [ngIf]="condition"><div>...</div></ng-template>
Use else block
<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 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() { = === ? : ; } ngOnInit() { = ; } }
Basic knowledge
TemplateRef
The TemplateRef instance is used to represent template objects. The definition of the TemplateRef abstract class is as follows:
// angular\packages\core\src\linker\template_ref.ts export abstract class TemplateRef<C> { abstract get elementRef(): ElementRef; abstract createEmbeddedView(context: C): EmbeddedViewRef<C>; }
ViewContainerRef
The ViewContainerRef instance provides createEmbeddedView()
method, this method receivesTemplateRef
The object is used as a parameter and the contents in the template are inserted into the page as sibling elements of the container (comment element).
NgIfContext
The NgIfContext instance is used to represent the NgIf context.
// angular\packages\common\src\directives\ng_if.ts export class NgIfContext { public $implicit: any = null; public ngIf: any = null; }
NgIf source code analysis
NgIf directive definition
@Directive({ selector: '[ngIf]' // Attribute selector - <ng-template [ngIf]="condition">})
NgIf class private properties and constructors
export class NgIf { // Create NgIfContext context private _context: NgIfContext = new NgIfContext(); // represents then template object private _thenTemplateRef: TemplateRef<NgIfContext>|null = null; // represents an else template object private _elseTemplateRef: TemplateRef<NgIfContext>|null = null; // Represents the EmbeddedViewRef view created based on the then template private _thenViewRef: EmbeddedViewRef<NgIfContext>|null = null; // Represents the EmbeddedViewRef view created based on the else template 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 directive } }
NgIf class input properties
@Input() set ngIf(condition: any) { this._context.$implicit = this._context.ngIf = condition; this._updateView(); // Update the 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 viewprivate _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 an embedded view of _thenViewRef if (!this._thenViewRef) { this._viewContainer.clear(); this._elseViewRef = null; if (this._thenTemplateRef) { this._thenViewRef = this._viewContainer.createEmbeddedView(this._thenTemplateRef, this._context); } } } else { // The value of the condition expression is false // If _elseViewRef is null and _elseTemplateRef exists, create an embedded view of _elseViewRef if (!this._elseViewRef) { this._viewContainer.clear(); this._thenViewRef = null; if (this._elseTemplateRef) { this._elseViewRef = this._viewContainer.createEmbeddedView(this._elseTemplateRef, this._context); } } } }
ngIf
The source code of the instruction is relatively simple, the most important thing is_updateView()
method. The most important function in this method is how to create embedded views based on template objects. Next, let's analyze itViewContainerRef
The object's createEmbeddedView()
method.
ViewContainerRef - createEmbeddedView()
Method signature
// angular\packages\core\src\linker\view_container_ref.ts export abstract class ViewContainerRef { /** * Create an Embedded View based on the TemplateRef object, and then insert it into the container according to the value specified by `index`. * If no value of `index` is specified, the newly created view will be 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\ class ViewContainerRef_ implements ViewContainerData { // ... createEmbeddedView<C>( templateRef: TemplateRef<C>, context?: C, index?: number): EmbeddedViewRef<C> { //Create the TemplateRef object createEmbeddedView() method to createEmbeddedViewRef object const viewRef = (context || <any>{}); // Insert into the view container according to the specified index value (viewRef, index); return viewRef; } } // ViewContainerData interface inherits from ViewContainerRef abstract classexport 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; }
By observingViewContainerRef_
In the class createEmbeddedView()
Method, we found that the method is called internallyTemplateRef
The object'screateEmbeddedView()
Method to create an embedded view. So let's analyze it nextTemplateRef
The object'screateEmbeddedView()
method.
TemplateRef - createEmbeddedView()
Method signature
// angular\packages\core\src\linker\template_ref.ts export abstract class TemplateRef<C> { abstract createEmbeddedView(context: C): EmbeddedViewRef<C>; }
Method implementation
// angular\packages\core\src\view\ class TemplateRef_ extends TemplateRef<any> implements TemplateData { // ... createEmbeddedView(context: any): EmbeddedViewRef<any> { return new ViewRef_(( this._parentView, this._def, this._def.element !.template !, context)); } } export interface TemplateData extends TemplateRef<any> { _projectedViews: ViewData[]; }
After reading the above source code, there is no doubt that we will continue to analyze nextServices
In the object createEmbeddedView()
method.
Services - createEmbeddedView()
Services object definition
// angular\packages\core\src\view\ export 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\ export function initServicesIfNeeded() { if (initialized) { return; } initialized = true; const services = isDevMode() ? createDebugServices() : createProdServices(); = ; = ; = ; = ; = ; = ; = ; = ; = ; = ; = resolveDep; = ; = ; = ; = ; = dirtyParentQueries; }
existinitServicesIfNeeded()
In the method, different Services objects are created according to the current schema. Next, let's take a lookcreateProdServices()
method:
function createProdServices() { return { setCurrentNode: () => {}, createRootView: createProdRootView, createEmbeddedView: createEmbeddedView // Other methods have been omitted}
createEmbeddedView() method
// angular\packages\core\src\view\ export 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 ViewData object const view = createView(, , parent, anchorDef, viewDef); // Initialize ViewData object - set the value of component and context attributes initView(view, , context); // Create nodes in the view, that is, set the attribute value of the array // const nodes = ; for(...) { ...; nodes[i] = nodeData; } createViewNodes(view); return view; }
At this time, it is found that if all methods are fully analyzed, there will be too much content. The source code analysis ends here. Interested readers please read the source code yourself (please forgive me for your readers). Next, let's summarize createEmbeddedView()
Method calling process:
ViewContainerRef_ -> createEmbeddedView() => TemplateRef_ -> createEmbeddedView() => Services -> createEmbeddedView() => Call createEmbeddedView()
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.