Как получить ссылку на компонент, связанный с ElementRef в Angular 2

У меня есть этот компонент в моем шаблоне:

<vector-editor  #scaleControl
                [x]="scaleX"
                [y]="scaleY"
                [z]="scaleZ" >               
</vector-editor>

vector-editor имеет следующую структуру:

export class VerticeControlComponent implements OnInit
{
    @Input() x: number;
    @Input() y: number;
    @Input() z: number;

    ...
}

В моем приложении я получаю ссылку на #scaleControl с помощью

@ViewChild('scaleControl') scaleControl: ElementRef;

Теперь, если я выведу scaleControl в консоль я получаю такой результат:

введите описание изображения здесь

Как видно, ссылка не является нулевой, и все свойства моего компонента есть. Я хочу получить доступ к этим свойствам, но в коде фактический тип scaleControl является ElementRef и не VectorEditorControl как видно на выходе. Из-за этого TypeScript не позволяет мне использовать this.scaleControl.x,

Я также пытался бросить ElementRef как это

var temp = <VectorEditorControl>this.scaleControl

но я получаю сообщение о том, что не могу разыграть ElementRef в VectorEditorControl

В конце концов я попытался получить доступ this.scaleControl.nativeElement но это не определено...

Что мне здесь не хватает?

3 ответа

Решение

Вы должны знать следующее об использовании декоратора свойств @ViewChild.

Он использует следующие свойства метаданных:

  • селектор - тип директивы или имя, используемое для запроса.
  • читать - читать другой токен из запрашиваемых элементов.

Из исходного кода:

export interface ViewChildDecorator {
  /**
   * You can use ViewChild to get the first element or the directive matching 
   * the selector from the
   * view DOM. If the view DOM changes, and a new child matches the selector,
   * the property will be updated.
   *
   * View queries are set before the `ngAfterViewInit` callback is called.
   *
   * **Metadata Properties**:
   *
   * * **selector** - the directive type or the name used for querying.
   * * **read** - read a different token from the queried elements.
   */
  (selector: Type<any>|Function|string, {read}?: {read?: any}): any;
  new (selector: Type<any>|Function|string, {read}?: {read?: any}): ViewChild;
}

Если вы не предоставите read параметр, @ViewChild() вернет:

  • экземпляр компонента, если есть.
  • ElementRef экземпляр, если не применен компонент
  • отличается от токена запрашиваемых элементов, если вы установили свойство read

Так что если вы хотите получить ElementRef от ребенка, который является компонентом angular2 (VerticeControlComponent) вам нужно явно сказать, используя read: ElementRef:

@ViewChild('scaleControl', {read: ElementRef}) scaleControl: ElementRef;

И тогда внутри хука ngAfterViewInit или позже вы можете написать this.scaleControl.nativeElement чтобы получить элемент DOM.

Обновить

Я написал рано:

  • отличается от токена запрашиваемых элементов, если вы установили свойство read

Теперь я хочу добавить, что именно мы можем прочитать:

  • ElementRef

  • TemplateRef

  • ViewContainerRef

  • поставщик

Что значит Provider значит здесь?

Это означает, что если мы определили какого-либо поставщика (в компоненте или директиве) для конкретного элемента, то мы можем прочитать его.

@Component({
  selector: 'child',
  template: `
   <h2>I'm child</h2>
  `,
  providers: [
    {
      provide: 'test', useValue: 'x'
    }
  ]
})
export class ChildComponent {

}

Таким образом, в потребителя этого компонента мы можем написать

@ViewChild(ChildComponent, { read: 'test' }) providerToken: string;

чтобы получить ценность x,

пример

Смотрите также:

На момент написания я рекомендую использовать следующий метод:

@ViewChild('scaleControl') scaleControl: ElementRef<VerticeControlComponent>;

Затем вы можете получить доступ к обоим типам.

  • ElementRef: использование scaleControl
  • VerticeControlComponent: использование scaleControl.nativeElement

Я получил эту ошибку два раза. Один раз в моем основном коде и второй раз в тестовом коде (спецификации).

Оба раза не хватало ссылок. Угловой компилятор (транспортер) не показывает никаких ошибок во время компиляции, но позже спокойно не предоставляет ссылку на

  1. Впервые я получил эту ошибку в основном коде abc.component.ts. Я помню, что на этот раз мы правильно включили ссылки, необходимые для этого ребенка, в этот abc.component.ts. Этот дочерний компонент был из другого модуля. Ошибка была устранена только после того, как этот дочерний компонент не был включен в файл module.ts

    объявления: [VectorEditorComponent,....],

  2. Второй раз мы столкнулись с этим в spec-файле. Я пытался проверить некоторые ожидания, что свойство дочернего компонента должно быть установлено. Я не получал экземпляр дочернего компонента, а вместо этого получал ElementRef. Здесь снова не было ошибки компиляции. Проблема была немного другой здесь. Я использовал No_Errors_Schema. Итак, хотя мы не включили компонент в файл спецификаций, angular не жаловался, а вместо этого установил ElementRef вместо дочернего компонента. Ошибка исчезла, когда мы импортировали модуль и предоставили это в настройках тестового стенда в файле спецификации.

Во втором случае я могу понять, что это произошло из-за ошибки схемы. Но в первом случае, я думаю, Angular команда нуждается в улучшении. Нет никаких намеков на то, почему компонент не был предоставлен, но предоставляется ElementRef.

Другие вопросы по тегам