4

For students who have a little exposure to Angular components, there should be no problem with the interaction between components.
What this article wants to pursue is to use a popular explanation to help me understand more accurately.

Zero, the foundation of knowledge

CSS selectors

Before introducing parent-child components, we must first understand a concept - selector, selector

When we define a new component, we must have this property:

@Component({
  selector: 'app-village-edit', ①
  templateUrl: './village-edit.component.html',
  styleUrls: ['./village-edit.component.scss']
})

Among them, ① is the selector , which is to tell other components that if you want to call my component, you must use the component's selector <selectorName></selectorName> to call.

Essentially, defines the HTML tag of the component, just like the common <p> tags and <button> tags.

1. What is a parent-child component

Just as the relationship between parents and children in reality is relative, a person assumes the role of a child for its parents, and assumes the role of a parent for its children.

Parent and child components are also relative.

Suppose, a component is in its own HTML template, when selectors (that is, specific HTML tags). We call this component parent component , and that called component is called child component .

Second, the parent component calls the method of the child component

Two classes are defined:

child.component.ts, its selector selector is: 'app-child'
parent.component.ts, its selector selector is: 'app-parent',

At this point, refer to the selector of the child component in the HTML of the parent component:

<app-child></app-child>

This completes the invocation of the child component.
At this point, if you load the parent component through routing, you will find that the child component will also be rendered at a specific location.

3. Passing values from parent component to child component

Child components receive data using the @input decorator

The value received by the child component from the parent component is stored in the variable of the child component.
Therefore, the only difference between the variable used to receive the passed value and the ordinary variable is to add a @input() annotation to the regular variable.

A normal variable is defined like this:

master = 'Master';

If it is used to receive passed values, just change it to this:

@Input() master = 'Master';

As such, the master variable defaults to the 'Master' string.

But if the parent component passes a value to it, the variable becomes the received value.

Parent component uses square brackets [] to send data

Call the child component in the normal way:

<app-child></app-child>

If the child component can receive data, you can use the method [propertyName] = value to pass the value.
E.g:

<app-child [master]="hero"> </app-child>

This can be achieved in this way: once the component is rendered, the master variable in the child component is the value of 'hero'.

When the variable value in the parent component changes, the child component also changes synchronously,
That is to say, the subcomponent can monitor the change information of the passed value .

Upgrade: Subcomponents listen to incoming data changes through the set method

In the above method, although the passed value can be monitored for changes, the limitation is that the subcomponent can only directly use the
If you want to or filter incoming values, you need to tweak the subcomponents a bit.

Normally, subcomponents receive parameters by adding the @Input decorator to the variable:

@Input() name = 'name';

If you want to process parameters, you only need to change the variable receiving the passed value into set method :

@Input() 
get name(): string { return this._name; }
set name(name: string) { 
    // 此处可以增加其他处理逻辑
    this._name = name; 
} 
private _name = '';

At this time, _name is an internal variable. When the parent component passes a value to the name attribute, it will automatically execute the set name method to assign a value to _name and add other processing logic.

Another upgrade: child components listen for incoming data changes through the ngOnChanges() lifecycle hook

The official documentation states: "When you need to monitor multiple, interactive input properties, ngOnChanges() is more appropriate than the property setter method."

Normally, subcomponents receive arguments by adding the @Input decorator to the variable:

@Input() param1 = 'string1';
@Input() param2 = 'string2';

When we want to monitor the changes of multiple variables and react, we can use the ngOnChanges() method:

@Input() param1 = 'string1';
@Input() param2 = 'string2';

ngOnChanges(changes: SimpleChanges) {  ①

    for (const propName in changes) {  ②
    
        // 通过变量名获取变化信息
        const changedProp = changes[propName];  
        // 获取上一个值
        const from = JSON.stringify(changedProp.previousValue); ③
        // 获取当前值
        const to = JSON.stringify(changedProp.currentValue);     ④
        // 此处可以添加其他处理过程了 ⑤
     } 
     
}

① When executing the ngOnChanges() method, you can use a SimpleChanges parameter to obtain the changes of all parameters of the current component.
② Obtain the previous value and current value of each parameter through a loop.
③ Get the last value of
④ Get the current value of
⑤ Add other processing procedures according to business logic

Note: Since the ngOnChanges method is called very frequently, it will cause performance problems or software crashes, so it is recommended to use it sparingly.

Fourth, the child component passes values to the parent component

Child component ejects event to parent component

I just talked about how the child component obtains the incoming variables of the parent component , how to monitor the changes of the parent component, and how to process the incoming values.

Next, we will talk about the reverse transmission: How the parent component listens to the changes of the child component and responds.

A normal variable is defined like this:

param1 = 'String1';

If you want to expose this variable to the parent component, you need to add the @output() decorator before the variable, and assign it a variable catapult :

@Output() param1 = new EventEmitter<string>();

Here EventEmitter is a variable catapult, and EventEmitter needs a type determined by .

But at this time, the param1 variable can no longer be assigned with the equal sign "=". If you want the parent component to monitor changes, you need to use the ejection method .emit :

this.param1.emit("String2");

Next go to the parent component.

The parent component listens to the event of the child component ejection

The exposed variables have just been set in the child component, so how does the parent component receive it?

A regular parent component calls a child component:

<app-child></app-child>

If you want to listen to a variable of a child component, you can use parentheses ():

<app-child (param1)="function1($event)">

</app-child>

$event is an event variable built into Angular.
function1 The method we define in the parent component to handle changes.
It is used as follows:

function1(param2: boolean) { 
    // 这个param2为我们自己定义的参数名,
    // 本质上是子组件中变化的param1参数,但不用和子组件中的参数名相同
    // 在此处增加处理过程即可
}

At this point, when the value of param1 changes, function1 will be executed, and an event will be passed in. The essence of the event is the param1 parameter defined by the subcomponent.
The function1 method receives the parameter as param2 and adds processing.

V. Summary

  • In Angular, a component called in HTML with the selector is called a subcomponent .
  • Use square brackets [] to pass values from parent components to child components
  • There are two ways for subcomponents to receive values: @input + variable name, @Input + set method
  • The child component wants the parent component to pass the event using EventEmitter
  • The parent component receives the event using parentheses () and declares a handler method to call

Familiar style, a picture is worth a thousand words:
Pasted image 20220321180019.png

6. Postscript

Does it feel familiar? When you first started to contact Angular, you knew that you can use square brackets [] to bind some attributes of native HTML tags , for example:

<p [id]="sayHelloId" [style.color]="fontColor">
    You can set my color in the component!
</p>

On the other hand, there is a similarity that Angular also uses parentheses () to bind a method of native HTML tags, for example:

<button (click)="onClick()"> 
    点我!
</button>

Are these coincidences? Not really.

We can understand it like this:

All native HTML tags in Angular become components .

The reason why many tags can use square brackets [] bind attributes, use parentheses () binding methods, is because Angular has extended native HTML tags for us, so that they have the ability to receive and send data. ability!

In other words, a lot of @input and @output decorators have been added to the components inside Angular, so that we can easily bind these properties and methods.


LYX6666
1.6k 声望75 粉丝

一个正在茁壮成长的零基础小白