
ng new ivy-internals tsconfig.json file located in the new project folder: "angularCompilerOptions": { "enableIvy": true } ngc command in the newly created project folder: node_modules/.bin/ngc dist/out-tsc . For example, take a look at the following fragment of the AppComponent template: <div style="text-align:center"> <h1> Welcome to {{ title }}! </h1> <img width="300" alt="Angular Logo" src="…"> </div> dist/out-tsc/src/app/app.component.js : i0.ɵE(0, "div", _c0); i0.ɵE(1, "h1"); i0.ɵT(2); i0.ɵe(); i0.ɵE(3, "img", _c1); i0.ɵe(); i0.ɵe(); i0.ɵE(4, "h2"); i0.ɵT(5, "Here are some links to help you start: "); i0.ɵe(); 
src/app/app.component.html ), compile it again and see how the changes made to it affect the generated code.i0.ɵE and i0.ɵT var i0 = require("@angular/core"); i0 is just an Angular kernel module, and all of these are functions exported by Angular. The letter ɵ used by the Angular development team to indicate that some methods are intended solely to support the internal mechanisms of the framework, that is, users should not call them directly, since the API’s invariance of these methods is not guaranteed when new versions of Angular are released (in fact, I would say that their API is almost guaranteed to change).
elementStart .ɵT is text , the name of the method ɵe is elementEnd . Armed with this knowledge, we can "translate" the generated code, turning it into something that will be easier to read. Here is a small piece of this "translation": var core = require("angular/core"); //... core.elementStart(0, "div", _c0); core.elementStart(1, "h1"); core.text(2); core. (); core.elementStart(3, "img", _c1); core.elementEnd(); core.elementEnd(); core.elementStart(4, "h2"); core.text(5, "Here are some links to help you start: "); core.elementEnd(); <div style="text-align:center"> <h1> Welcome to {{ title }}! </h1> <img width="300" alt="Angular Logo" src="…"> </div> core.elementStart() .core.elementEnd() calls.core.text() calls.elementStart and text methods is a number, the value of which increases with each call. It is probably an index in some kind of array in which Angular stores references to the created elements.elementStart method. After studying the above materials, we can conclude that the argument is optional and contains a list of attributes for the DOM node. You can check this by looking at the _c0 value and finding out that it contains a list of attributes and their values for the div element: var _c0 = ["style", "text-align:center"]; AppComponent.ngComponentDef , a static property that contains all the metadata about the component, such as CSS selectors, its change detection strategy (if specified), and the template. If you feel adventurous, you can now figure out how it works, although we'll talk about it below. import { Component } from '@angular/core'; @Component({ selector: 'manual-component', template: '<h2><font color="#3AC1EF">Hello, Component</font></h2>', }) export class ManualComponent { } @component decorator, creates instructions, and then draws it all in the form of a static property of the component class. Therefore, in order to imitate the activity of Ivy, we remove the @component decorator and replace it with the ngComponent static property: import * as core from '@angular/core'; export class ManualComponent { static ngComponentDef = core.ɵdefineComponent({ type: ManualComponent, selectors: [['manual-component']], factory: () => new ManualComponent(), template: (rf: core.ɵRenderFlags, ctx: ManualComponent) => { // }, }); } ɵdefineComponent . Metadata includes the type of component (used earlier for dependency injection), the CSS selector (or selectors) that will call this component (in our case, manual-component is the name of the component in the HTML template), a factory that returns a new instance component, and then the function that defines the pattern for the component. This template displays a visual representation of the component and updates it when the component properties change. In order to create this template, we will use the methods that we found above: ɵE , ɵe and ɵT . template: (rf: core.ɵRenderFlags, ctx: ManualComponent) => { core.ɵE(0, 'h2'); // h2 core.ɵT(1, 'Hello, Component'); // core.ɵe(); // h2 }, rf or ctf parameters provided by our template function. We will come back to them. But first, let's look at how to bring our first homemade component to the screen.ɵrenderComponent . All that needs to be done is to check that the index.html file has an HTML tag that corresponds to the element selector, <manual-component> , and then add the following to the end of the file: core.ɵrenderComponent(ManualComponent); Hello, Component , we are going to allow the user to change the part of the text that comes after Hello .name property and the method to update the value of this property to the component class: export class ManualComponent { name = 'Component'; updateName(newName: string) { this.name = newName; } // ... } name property: template: (rf: core.ɵRenderFlags, ctx: ManualComponent) => { if (rf & 1) { // : core.ɵE(0, 'h2'); core.ɵT(1, 'Hello, '); core.ɵT(2); // <-- name core.ɵe(); } if (rf & 2) { // : core.ɵt(2, ctx.name); // ctx - } }, if expressions that check the rf values. This parameter is used by Angular to indicate whether the component is being created for the first time (the least significant bit will be set ), or we just need to update the dynamic content during the change detection process (this is the second if expression that is directed).ɵt responsible for this (note the lower-case letter t ), which corresponds to the textBinding function exported by Angular:
core.ɵT(2); command core.ɵT(2); . It plays the role of placeholder for name . We update it with the core.ɵt(2, ctx.name); command core.ɵt(2, ctx.name); when a change in the corresponding variable is detectedHello, Component will still appear, although we can change the value of the name property, which will change the text on the screen.updateName() component method: template: (rf: core.ɵRenderFlags, ctx: ManualComponent) => { if (rf & 1) { core.ɵE(0, 'h2'); core.ɵT(1, 'Hello, '); core.ɵT(2); core.ɵe(); core.ɵT(3, 'Your name: '); core.ɵE(4, 'input'); core.ɵL('input', $event => ctx.updateName($event.target.value)); core.ɵe(); } // ... }, core.ɵL('input', $event => ctx.updateName($event.target.value)); line core.ɵL('input', $event => ctx.updateName($event.target.value)); . Namely, the ɵL method ɵL responsible for setting the event listener for the most recent of the declared elements. The first argument is the name of the event (in this case, input is the event that is called when the content of the <input> element changes), the second argument is the callback. This callback accepts event data as an argument. Then we retrieve the current value from the target element of the event, that is, from the <input> element, and pass it to the function in the component. Your name: <input (input)="updateName($event.target.value)" /> <input> element and observe how the text in the component changes. However, the input field is not filled when the component is loaded. In order for everything to work that way, you need to add another instruction to the template function code that is executed when a change is detected: template: (rf: core.ɵRenderFlags, ctx: ManualComponent) => { if (rf & 1) { ... } if (rf & 2) { core.ɵt(2, ctx.name); core.ɵp(4, 'value', ctx.name); } } ɵp , which updates the property of an element with a given index. In this case, the method is passed an index of 4, which is the index assigned to the input element, and instructs the method that it should put the value of ctx.name in the value property of this element.*ngIf or *ngFor . They are processed in a special way. Let's look at how to use *ngIf in the code of our self-made template.@angular/common npm-package - it is here that *ngIf . Next, you need to import the directive from this package: import { NgIf } from '@angular/common'; NgIf in a template, you need to provide it with some metadata, since the @angular/common module was not compiled using Ivy (at least during the writing of the material, and in the future this will probably change from introduction ngcc ).ɵdefineDirective method, which is related to the already familiar ɵdefineComponent method. It defines metadata for directives: (NgIf as any).ngDirectiveDef = core.ɵdefineDirective({ type: NgIf, selectors: [['', 'ngIf', '']], factory: () => new NgIf(core.ɵinjectViewContainerRef(), core.ɵinjectTemplateRef()), inputs: {ngIf: 'ngIf', ngIfThen: 'ngIfThen', ngIfElse: 'ngIfElse'} }); ngFor . Now that we have prepared NgIf for use in Ivy, we can add the following to the list of directives for the component: static ngComponentDef = core.ɵdefineComponent({ directives: [NgIf], // ... }); *ngIf . function ifTemplate(rf: core.ɵRenderFlags, ctx: ManualComponent) { if (rf & 1) { core.ɵE(0, 'div'); core.ɵE(1, 'img', ['src', 'https://pbs.twimg.com/tweet_video_thumb/C80o289UQAAKIqp.jpg']); core.ɵe(); } } img element inside the div element.ngIf directive to the component template: template: (rf: core.ɵRenderFlags, ctx: ManualComponent) => { if (rf & 1) { // ... core.ɵC(5, ifTemplate, null, ['ngIf']); } if (rf & 2) { // ... core.ɵp(5, 'ngIf', (ctx.name === 'Igor')); } function ifTemplate(rf: core.ɵRenderFlags, ctx: ManualComponent) { // ... } }, core.ɵC(5, ifTemplate, null, ['ngIf']); ). It declares a new container element, that is, an element that has a template. The first argument is the element index; we have already seen such indexes. The second argument is the sub-template function that we have just defined. It will be used as a template for the container element. The third parameter is the tag name for the element, which does not make sense here, and finally there is a list of directives and attributes associated with this element. This is where ngIf comes into ngIf .core.ɵp(5, 'ngIf', (ctx.name === 'Igor')); the element state is updated by binding the ngIf attribute to the value of the logical expression ctx.name === 'Igor' . Here we check whether the name property of the component is equal to the string Igor . <div *ngIf="name === 'Igor'"> <img align="center" src="..."> </div> NgIf section in action, enter the name Igor in the field Your name .
Source: https://habr.com/ru/post/419995/
All Articles