web-dev-qa-db-fra.com

Angular 2 @ViewChild renvoie undefined

J'ai consulté plusieurs publications et documents liés, mais je n'arrive toujours pas à obtenir le comportement attendu de @ViewChild. 

En fin de compte, j'essaie de définir la position de défilement d'une div. Cet élément n'est pas un composant, mais une div normale dans mon code HTML. 

Pour ce faire, j'essaie d'utiliser @ViewChild pour obtenir l'élément DOM dont j'ai besoin et définir sa valeur de défilement. (En passant, si vous connaissez un meilleur moyen d'y parvenir sans @ViewChild (ou jQuery), les réponses seront très appréciées!)

Pour le moment, @ViewChild ne renvoie qu'un indéfini. En passant par des vérifications factices: - J'accède à mon élément dans AfterViewInit - Je n'ai pas d'autres directives comme * ngIf ou * ngFor sur cet élément.

Voici le contrôleur:

import { Component, AfterViewInit, ViewChild, ElementRef } from '@angular/core';

@Component({
    selector: 'portfolio-page',
    templateUrl: './portfolio-page.component.html',
    styleUrls: ['./portfolio-page.component.scss']
})

export class PortfolioPageComponent implements AfterViewInit{
    @ViewChild('gallery-container') galleryContainer: ElementRef;

    ngAfterViewInit(){
        console.log('My element: ' + this.galleryContainer);
    }
}

Et le modèle:

<div id='gallery-container' class='gallery-image-container'>
    <div class='gallery-padding'></div>
    <img class='gallery-image' src='{{ coverPhotoVm }}' />
    <img class='gallery-image' src='{{ imagepath }}' *ngFor='let imagepath of imagesVm' />
</div>

Ma sortie est simple: Mon élément: non défini.

Comme vous pouvez le constater, j'essaie actuellement d'accéder à l'élément par ID, mais j'ai également essayé le nom de la classe. Quelqu'un pourrait-il fournir plus de détails sur les attentes de la requête du sélecteur ViewChild?

J'ai aussi vu des exemples où un hash '#' est utilisé comme identifiant de sélecteur utilisé par @ViewChild - - mais cela provoque une erreur d'analyse de modèle pour moi avec # gallery-container.

Je ne peux penser à rien d'autre qui pourrait se tromper ici. Toute aide est appréciée, merci!

Le code complet est disponible ici: https://github.com/aconfee/KimbyArting/tree/master/client/KimbyArting/components/portfolio-page

21
Adam

Essayez plutôt d’utiliser une référence dans votre modèle:

<div id='gallery-container' #galleryContainer class='gallery-image-container'>
    <div class='gallery-padding'></div>
    <img class='gallery-image' src='{{ coverPhotoVm }}' />
    <img class='gallery-image' src='{{ imagepath }}' *ngFor='let imagepath of imagesVm' />
</div>

Et utilisez le nom de référence comme argument:

@ViewChild('galleryContainer') galleryContainer: ElementRef;

MODIFIER

Oublié de mentionner que toute vue ainsi déclarée n'est disponible qu'une fois la vue initialisée. Ceci se produit pour la première fois dans ngAfterViewInit (importez et implémentez l'interface AfterViewInit).

Le nom de la référence ne doit pas contenir de tirets, sinon cela ne fonctionnera pas

43
Aviad P.

Parfois, si le composant n’est pas encore initialisé lorsque vous y accédez, vous obtenez une erreur indiquant que le composant enfant n’est pas défini.

Toutefois, même si vous accédez au composant enfant dans AfterViewInit, parfois @ViewChild renvoyait toujours la valeur null. Le problème peut être causé par la * ngIf ou une autre directive.

La solution consiste à utiliser @ViewChildren à la place de @ViewChild et à abonner l'abonnement aux modifications exécuté lorsque le composant est prêt.

Par exemple, si vous voulez accéder au composant enfant MyComponent dans le composant parent ParentComponent.

import { Component, ViewChildren, AfterViewInit, QueryList } from '@angular/core';
import { MyComponent } from './mycomponent.component';

export class ParentComponent implements AfterViewInit
{
  //other code emitted for clarity

  @ViewChildren(MyComponent) childrenComponent: QueryList<MyComponent>;

  public ngAfterViewInit(): void
  {
    this.childrenComponent.changes.subscribe((comps: QueryList<MyComponent>) =>
    {
      // Now you can access the child component
    });
  }
}
11
Marco Barbero

S'abonner aux modifications sur 

@ViewChildren(MyComponent) childrenComponent: QueryList<MyComponent>

travail confirmé, combiné avec setTimeout() et notifyOnChanges() et une vérification minutieuse de null.

Toute autre approche produit des résultats peu fiables et est difficile à tester.

1
Martin Stetina

J'ai eu un problème similaire. Contrairement à vous, mon @ViewChild a retourné une ElementRef valide, mais lorsque j'ai essayé d'accéder à sa nativeElement, c'était undefined.

Je l'ai résolu en définissant la vue id comme #content, pas comme #content = "ngModel".

<textarea type = "text"
    id = "content"
    name = "content"
    #content
    [(ngModel)] = "article.content"
    required></textarea>
0
Yamashiro Rion