ฉันจะใช้ตัวเลือกคงที่ใหม่สำหรับ @ViewChild ใน Angular 8 ได้อย่างไร


204

ฉันควรกำหนดค่าลูกมุมมอง Angular 8 ใหม่ได้อย่างไร

@ViewChild('searchText', {read: ElementRef, static: false})
public searchTextInput: ElementRef;

VS

@ViewChild('searchText', {read: ElementRef, static: true})
public searchTextInput: ElementRef;

ไหนดีกว่ากัน เมื่อฉันควรใช้static:trueVS static:false?

คำตอบ:


237

{static: false}ในกรณีส่วนใหญ่คุณจะต้องการใช้ การตั้งค่าเช่นนี้จะช่วยให้มั่นใจว่าการค้นหาที่ตรงกันนั้นขึ้นอยู่กับการแก้ปัญหาการเชื่อมโยง (เช่นคำสั่งโครงสร้าง*ngIf, etc...)

ตัวอย่างของการใช้เมื่อstatic: false:

@Component({
  template: `
    <div *ngIf="showMe" #viewMe>Am I here?</div>
    <button (click)="showMe = !showMe"></button>
  ` 
})
export class ExampleComponent {
  @ViewChild('viewMe', { static: false })
  viewMe?: ElementRef<HTMLElement>; 

  showMe = false;
}

สิ่งstatic: falseนี้จะเป็นพฤติกรรมทางเลือกเริ่มต้นใน Angular 9 อ่านเพิ่มเติมที่นี่และที่นี่

{ static: true }ตัวเลือกที่ถูกนำไปสนับสนุนการสร้างมุมมองที่ฝังตัวในการบิน เมื่อคุณสร้างมุมมองแบบไดนามิกและต้องการเห็นTemplateRefด้วยคุณจะไม่สามารถทำได้ngAfterViewInitเนื่องจากจะทำให้เกิดExpressionHasChangedAfterCheckedข้อผิดพลาด การตั้งค่าสถานะคงที่เป็นจริงจะสร้างมุมมองของคุณใน ngOnInit

แต่ถึงอย่างไร:

ในกรณีอื่น ๆ {static: false}ส่วนใหญ่ปฏิบัติที่ดีที่สุดคือการใช้งาน

โปรดทราบว่า{ static: false }ตัวเลือกจะเริ่มต้นใน Angular 9 ซึ่งหมายความว่าการตั้งค่าสถานะคงที่ไม่จำเป็นอีกต่อไปเว้นแต่ว่าคุณต้องการใช้static: trueตัวเลือก

คุณสามารถใช้ng updateคำสั่งangular cli เพื่ออัพเกรดฐานรหัสปัจจุบันของคุณโดยอัตโนมัติ

สำหรับคำแนะนำในการย้ายถิ่นและข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้คุณสามารถตรวจสอบได้ที่นี่และที่นี่

ข้อแตกต่างระหว่างแบบสอบถามแบบคงที่และแบบไดนามิกคืออะไร

ตัวเลือกคงที่สำหรับแบบสอบถาม @ViewChild () และ @ContentChild () กำหนดเมื่อผลลัพธ์ของแบบสอบถามพร้อมใช้งาน

ด้วยแบบสอบถามแบบคงที่ (คงที่: จริง) แบบสอบถามจะแก้ไขเมื่อสร้างมุมมองแล้ว แต่ก่อนที่การตรวจจับการเปลี่ยนแปลงจะทำงาน อย่างไรก็ตามผลลัพธ์จะไม่ได้รับการอัปเดตเพื่อแสดงการเปลี่ยนแปลงในมุมมองของคุณเช่นการเปลี่ยนแปลงในบล็อก ngIf และ ngFor

ด้วยการสืบค้นแบบไดนามิก (คงที่: เท็จ) แบบสอบถามจะแก้ไขหลังจาก ngAfterViewInit () หรือ ngAfterContentInit () สำหรับ @ViewChild () และ @ContentChild () ตามลำดับ ผลลัพธ์จะได้รับการอัปเดตสำหรับการเปลี่ยนแปลงในมุมมองของคุณเช่นการเปลี่ยนแปลงในบล็อก ngIf และ ngFor


โปรดอัปเดตลิงก์สำหรับเอกสารเชิงมุม (เปลี่ยนหลังจากเผยแพร่) angular.io/api/core/ViewChild#description
Sachin Gupta

2
ฉันไม่สามารถเข้าถึงอินสแตนซ์ของ childView ได้ มันบอกว่าไม่ได้กำหนดตลอดเวลา
Nesan Mano

คุณสามารถให้ลิงค์เกี่ยวกับข้อมูลของการลบตัวเลือกคงที่ใน Angular 9 ได้หรือไม่?
Alex Marinov

@AlexMarinov ฉันได้อัปเดตคำตอบของฉันเพื่อให้ชัดเจนยิ่งขึ้นว่าจะเกิดอะไรขึ้นในเชิงมุม 9. ลิงก์เกี่ยวกับสิ่งนี้อยู่ในคู่มือการย้ายถิ่น
Poul Kruijt

1
@ MinhNghĩaถ้าคุณรังนอกองค์ประกอบทั้งหมดของแม่แบบองค์ประกอบของคุณสามารถใช้{ static: true }แต่ถ้ามีความจำเป็นโดยตรงที่มีการเข้าถึงภายใน ViewChild คุณควรใช้เพียงngOnInit { static: false }
Poul Kruijt

88

เพื่อเป็นกฎง่ายๆคุณสามารถไปต่อไปนี้:

  • { static: true }จำเป็นต้องตั้งค่าเมื่อคุณต้องการในการเข้าถึงในViewChildngOnInit

  • { static: false }ngAfterViewInitสามารถเข้าถึงได้เฉพาะใน นี่คือสิ่งที่คุณต้องการใช้เมื่อคุณมีคำสั่งโครงสร้าง (เช่น*ngIf) ในองค์ประกอบของคุณในแม่แบบของคุณ


2
หมายเหตุ: ใน Angular 9 ค่าเริ่มต้นของธงแบบคงที่เป็นเท็จดังนั้น "ค่าสถานะ {static: false} ใด ๆ สามารถลบออกได้อย่างปลอดภัย" เอกสารประกอบ: angular.io/guide/static-query-migration
Stevethemacguy

17

จากเอกสารเชิงมุม

คงที่ - ไม่ว่าจะแก้ไขผลการสืบค้นก่อนที่จะตรวจจับการเปลี่ยนแปลงการทำงาน (เช่นผลตอบแทนคงที่เท่านั้น) หากไม่มีตัวเลือกนี้คอมไพเลอร์จะถอยกลับไปที่การทำงานเริ่มต้นซึ่งจะใช้ผลลัพธ์ของแบบสอบถามเพื่อกำหนดเวลาของการแก้ไขแบบสอบถาม หากผลการสืบค้นใด ๆ อยู่ในมุมมองแบบซ้อน (เช่น * ngIf) แบบสอบถามจะได้รับการแก้ไขหลังจากตรวจพบการเปลี่ยนแปลง มิฉะนั้นจะได้รับการแก้ไขก่อนที่การตรวจจับการเปลี่ยนแปลงจะทำงาน

มันอาจจะเป็นความคิดที่ดีกว่าที่จะใช้static:trueถ้าเด็กไม่ได้ขึ้นอยู่กับเงื่อนไขใด ๆ หากการมองเห็นขององค์ประกอบมีการเปลี่ยนแปลงก็static:falseอาจให้ผลลัพธ์ที่ดีกว่า

PS: เนื่องจากเป็นคุณสมบัติใหม่เราอาจต้องเรียกใช้เกณฑ์มาตรฐานเพื่อประสิทธิภาพ

แก้ไข

ดังที่ @Massimiliano Sartoretto, GitHub กระทำอาจทำให้คุณมีข้อมูลเชิงลึกมากขึ้น


3
ฉันจะเพิ่มแรงจูงใจอย่างเป็นทางการที่อยู่เบื้องหลังคุณลักษณะนี้github.com/angular/angular/pull/28810
Massimiliano Sartoretto

2

มาที่นี่เพราะ ViewChild เป็นโมฆะใน ngOnInit หลังจากอัปเกรดเป็น Angular 8

แบบสอบถามแบบคงที่จะถูกกรอกก่อน ngOnInit ในขณะที่แบบสอบถามแบบไดนามิก (คงที่: เท็จ) จะถูกกรอกหลัง กล่าวอีกนัยหนึ่งถ้าตอนนี้ viewchild เป็นโมฆะใน ngOnInit หลังจากที่คุณตั้งค่าสแตติก: false คุณควรพิจารณาเปลี่ยนเป็นสแตติก: จริงหรือย้ายโค้ดเป็น ngAfterViewInit

ดูhttps://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L332-L336

คำตอบอื่น ๆ นั้นถูกต้องและอธิบายว่าทำไมในกรณีนี้: การค้นหาขึ้นอยู่กับคำสั่งโครงสร้างเช่นการอ้างอิง ViewChild ใน ngIf ควรเรียกใช้หลังจากเงื่อนไขของคำสั่งนี้ได้รับการแก้ไขคือหลังจากตรวจจับการเปลี่ยนแปลง อย่างไรก็ตามหนึ่งอาจใช้แบบคงที่: จริงและแก้ไขแบบสอบถามก่อนที่จะ ngOnInit สำหรับการอ้างอิงที่ไม่ได้ทดสอบ กรณีนี้โดยเฉพาะ Imho หมีที่กล่าวถึงเป็นข้อยกเว้นอาจเป็นวิธีแรกที่คุณจะได้พบกับความพิเศษนี้เช่นเดียวกับฉัน


1

ดู child @angular 5+ โทเค็นสองอาร์กิวเมนต์ ('ชื่ออ้างอิงในพื้นที่', static: false | true)

@ViewChild('nameInput', { static: false }) nameInputRef: ElementRef;

เพื่อทราบความแตกต่างระหว่างจริงและเท็จตรวจสอบเรื่องนี้

คงที่ - ไม่ว่าจะแก้ไขผลแบบสอบถามก่อนที่จะตรวจจับการเปลี่ยนแปลงการทำงาน (เช่นผลตอบแทนคงที่เท่านั้น) หากไม่มีตัวเลือกนี้คอมไพเลอร์จะถอยกลับไปที่การทำงานเริ่มต้นซึ่งจะใช้ผลลัพธ์ของแบบสอบถามเพื่อกำหนดเวลาของการแก้ไขแบบสอบถาม หากผลการสืบค้นใด ๆ อยู่ในมุมมองแบบซ้อน (เช่น * ngIf) แบบสอบถามจะได้รับการแก้ไขหลังจากตรวจพบการเปลี่ยนแปลงการเรียกใช้ มิฉะนั้นจะสามารถแก้ไขได้ก่อนที่การตรวจจับการเปลี่ยนแปลงจะทำงาน


0

ใน ng8 คุณสามารถตั้งค่าได้ด้วยตนเองเมื่อเข้าถึงส่วนประกอบลูกในองค์ประกอบหลัก เมื่อคุณตั้งค่าสแตติกเป็นจริงมันหมายถึงองค์ประกอบหลักเท่านั้นที่ได้รับความหมายขององค์ประกอบในonInitเบ็ด: เช่น:

 // You got a childComponent which has a ngIf/for tag
ngOnInit(){
  console.log(this.childComponent);
}

ngAfterViewInit(){
  console.log(this.childComponent);
}

หากสแตติกเป็นเท็จคุณจะได้รับการกำหนดใน ngAfterViewInit () ใน ngOnInit () คุณจะไม่ได้กำหนด

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.