Как мне использовать новую статическую опцию для @ViewChild в Angular 8?

204

Как настроить новый дочерний элемент Angular 8?

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

против

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

Что лучше? Когда я должен использовать static:trueпротив 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: falseAngular 9 будет использоваться резервное поведение по умолчанию. Подробнее читайте здесь и здесь

{ static: true }Опция была введена для поддержки создания встраиваемых взглядов на лету. Когда вы динамически создаете представление и хотите получить доступ к нему TemplateRef, вы не сможете сделать это, так ngAfterViewInitкак это приведет к ExpressionHasChangedAfterCheckedошибке. Установка статического флага в true создаст ваше представление в ngOnInit.

тем не менее:

В большинстве других случаев наилучшей практикой является использование {static: false}.

Имейте { static: false }в виду, что в Angular 9 этот параметр будет установлен по умолчанию. Это означает, что установка статического флага больше не требуется, если только вы не хотите использовать этот static: trueпараметр.

Вы можете использовать команду angular cli ng updateдля автоматического обновления текущей базы кода.

Для руководства по миграции и даже больше информации об этом вы можете проверить здесь и здесь

В чем разница между статическими и динамическими запросами?

Статическая опция для запросов @ViewChild () и @ContentChild () определяет, когда станут доступны результаты запроса.

В случае статических запросов (static: true) запрос разрешается после создания представления, но до запуска обнаружения изменений. Результат, однако, никогда не будет обновляться, чтобы отражать изменения в вашем представлении, такие как изменения в блоках ngIf и ngFor.

При динамических запросах (static: false) запрос разрешается после ngAfterViewInit () или ngAfterContentInit () для @ViewChild () и @ContentChild () соответственно. Результат будет обновлен для изменений в вашем представлении, таких как изменения блоков ngIf и ngFor.

Пол Круйт
источник
Пожалуйста, обновите ссылку на угловые документы (изменено после выпуска) angular.io/api/core/ViewChild#description
Sachin Gupta
2
Я не могу получить доступ к экземпляру childView. Это говорит неопределенное все время.
Несан Мано
Можете ли вы предоставить ссылку на эту информацию об удалении статической опции в Angular 9?
Алексей Маринов
@AlexMarinov Я обновил свой ответ, чтобы было более понятно, что произойдет в угловом 9. Ссылка на это есть в руководстве по миграции
Poul Kruijt
1
@ MinhNghĩa, если вы вкладываете весь компонент вне шаблона компонента, вы можете использовать его { static: true }, но если нет прямой необходимости иметь доступ к ViewChild внутри ngOnInit, вам просто нужно использовать { static: false }.
Poul Kruijt
88

Так что, как правило, вы можете пойти на следующее:

  • { static: true }должен быть установлен , если вы хотите получить доступ к ViewChildин ngOnInit.

  • { static: false }можно получить доступ только в ngAfterViewInit. Это также то, к чему вы хотите стремиться, когда у вас есть структурная директива (то есть *ngIf) для вашего элемента в шаблоне.

dave0688
источник
2
Примечание. В Angular 9 для статического флага по умолчанию установлено значение false, поэтому «любые флаги {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
Массимилиано Сарторетто
2

Пришел сюда, потому что ViewChild был нулевым в ngOnInit после обновления до Angular 8.

Статические запросы заполняются до ngOnInit, а динамические запросы (статические: ложь) - после. Другими словами, если viewchild теперь равен null в ngOnInit после того, как вы установили static: false, вам следует рассмотреть возможность изменения на static: true или переместить код в ngAfterViewInit.

См. Https://github.com/angular/angular/blob/master/packages/core/src/view/view.ts#L332-L336.

Другие ответы верны и объясняют, почему это так: запросы, зависящие от структурных директив, например, ссылка ViewChild внутри ngIf, должны выполняться после разрешения условия этой директивы, то есть после обнаружения изменения. Однако можно смело использовать static: true и, таким образом, разрешать запросы перед ngOnInit для неопубликованных ссылок. Имхо, этот конкретный случай должен упоминаться как нулевое исключение, вероятно, будет первым способом, с которым вы столкнетесь с этой особенностью, как это было для меня.

венчик
источник
1

просмотреть дочерний токен @+ 5+ с двумя аргументами («имя локальной ссылки», статический: false | true)

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

чтобы узнать разницу между истинным и ложным, проверьте это

статический - разрешать или не разрешать результаты запроса перед выполнением обнаружения изменений (т.е. возвращать только статические результаты). Если эта опция не указана, компилятор вернется к своему поведению по умолчанию, которое будет использовать результаты запроса для определения времени разрешения запроса. Если какие-либо результаты запроса находятся во вложенном представлении (например, * ngIf), запрос будет разрешен после выполнения обнаружения изменений. В противном случае оно будет разрешено до запуска обнаружения изменений.

Самар Абдалла
источник
0

В ng8 вы можете вручную установить, когда обращаться к дочернему компоненту в родительском компоненте. Когда вы устанавливаете static в true, это означает, что родительский компонент получает только определение компонента в onInitхуке: Например:

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

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

Если static равно false, то вы получите определение только в ngAfterViewInit (), а в ngOnInit () вы получите неопределенное значение.

Тетис Чжан
источник