web-dev-qa-db-fra.com

@ViewChild ne pas initialiser pendant Ngoninit

Je gère deux mâtables dans différents composants avec des sources de données de différents observables. Une de mes formes de tri fonctionne bien fonctionne bien et mais sur ma deuxième table, il semble que le @ViewChild pour Matsort ne s'initialise pas pendant Ngoninit.

Les rendements de données et la table de matériaux ont des boutons de tri, mais la fonctionnalité n'est rien. Vérifié mes importations et le module et tout va bien.
[.____] lors de la journalisation du MATSORT One composant enregistre un objet de matsort et l'autre est indéfini

Le tri ne fonctionne pas.

Feed.component:

   import { PostService } from './../../services/post.service';
   import { Post } from './../../models/post';
   import { Component, OnInit, ViewChild, ChangeDetectorRef} from 
     '@angular/core';
   import { MatSort, MatTableDataSource, MatCheckbox, MatPaginator, 
     MatTabChangeEvent, MatDialog, MatDialogActions, MatTable}  from 
   "@angular/material"



export class FeedComponent implements OnInit {
  @ViewChild(MatSort) sort: MatSort;
  @ViewChild(MatPaginator) paginator: MatPaginator;
  postData: Post[] =[];
  dataSource : MatTableDataSource<any> 
  currentUser = JSON.parse(localStorage.getItem('user'))
  displayedColumns:string[] = ['User','Title', "Description", 
  "Contact" ]
  posts = this.ps.getPosts();

  constructor(private ps: PostService, public dialog:MatDialog, 
    public change:ChangeDetectorRef, public ms:MessageService) { 

  }



refreshPosts(){
   console.log(this.sort) < -------comes back undefined
  this.posts.subscribe(posts=>{
    this.dataSource.sort = this.sort
     this.postData = posts.filter(post => post.uid != 
       `${this.currentUser.uid}` && post.claimedBy 
        !=`${this.currentUser.uid}`);
     this.dataSource= new MatTableDataSource(this.postData)
     this.dataSource.paginator = this.paginator;
    });

  }
ngOnInit() {
   this.refreshPosts()
   console.log(this.sort)
   }


Post.service
  getPosts(){
    return  this.afs.collection('posts').snapshotChanges()
     .pipe(map(actions => 
     actions.map(this.documentToDomainObject)))
  }
 documentToDomainObject = _ => {
  const object = _.payload.doc.data();
  object.id = _.payload.doc.id;
  return object;
}

Maintenant, mon prochain composant initialise de la même manière, mais le @viewchild apparaît comme un objet de matsort

Message.component:

export class MessageComponent implements OnInit {


 @ViewChild(MatSort) sort: MatSort;
  userReceived: MatTableDataSource<any>;
  userSent: MatTableDataSource<any>;
  displayedColumns:string[] = ["createdAt",'author',"title", "Delete"]
  sentColumns:string[] = ["createdAt","recipient", "title", "Delete"]


  currentUserId= this.currentUser['uid']
  currentUsername = this.currentUser['displayName']
  recipient:any;
  selectedMessage: MatTableDataSource<Message>;
  messageColumns= ['From','Title',"Body"];




  constructor(public ms:MessageService, public change:ChangeDetectorRef, public dialog: MatDialog  ) { }

  ngOnInit() {
    console.log(this.sort)
    this.updateMessages()
    this.currentUserId = this.currentUserId;
    this.currentUsername = this.currentUsername;

 }


updateMessages(){
    this.ms.getUserSent().subscribe(messages => {
      console.log(this.sort) <------logs MatSort object
      this.userSent = new MatTableDataSource(messages)
      this.userSent.sort = this.sort
      console.log(this.userSent.sort)
      console.log(this.userSent.data)

    })

message.Service

 getUserSent() {
    let messages:any[] = [];
    this.userSent = this.afs
      .collection('messages', ref => ref.where('uid', '==', `${this.currentUser.uid}`)).snapshotChanges() 
return this.userSent
  }

feed.component.html

<div class = "mat-elevation-z8">
    <mat-form-field>
        <input matInput (keyup)="applyFilter($event.target.value)" placeholder="Search Posts">
      </mat-form-field>
  <table matSort mat-table [dataSource]="dataSource" style="text-align:left">
      <ng-container matColumnDef="User">
          <th mat-header-cell *matHeaderCellDef mat-sort-header>User</th>
          <td mat-cell *matCellDef="let post">{{post.displayName}}</td>
       </ng-container>

  <ng-container matColumnDef="Title">
    <th mat-header-cell *matHeaderCellDef>Title</th>
    <td mat-cell *matCellDef="let post">{{post.title | truncate:15:false }}</td>
 </ng-container>

  <ng-container matColumnDef="Description">
    <th mat-header-cell *matHeaderCellDef >Description</th>
    <td mat-cell *matCellDef="let post">{{post.description | truncate: 20 : false}}</td>
  </ng-container>





  <ng-container matColumnDef="Contact">
    <th mat-header-cell *matHeaderCellDef> Contact </th>
    <td mat-cell *matCellDef="let post">
      <button  id="{{post.id}}" color="primary" (click)="openDialog($event.target.id)" style = "outline:none" value={{post.id}}>Claim</button>
    </td>

  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef='let row; columns: displayedColumns'></tr>
</table>
</div>
  <mat-paginator [length]="this.postData.length" [pageSize]="5" [pageSizeOptions]="[5,10,25]"></mat-paginator>

Je ne trouve vraiment pas pourquoi dans mon premier composant, les retours de tri non définis quand dans mon deuxième, composant de travail, il revient et objet. Est-ce que je manque quelque chose à propos de l'ordre de @viewchild?

9
Timotronadon

le problème dans FeedComponent est que vous créez this.dataSource.sort = this.sort affectation avant d'initialiser this.dataSource

refreshPosts(){
  console.log(this.sort) < -------comes back undefined
  this.posts.subscribe(posts=>{
     this.postData = posts.filter(post => post.uid != `${this.currentUser.uid}` && post.claimedBy !=`${this.currentUser.uid}`);
     this.dataSource= new MatTableDataSource(this.postData)
     this.dataSource.sort = this.sort // make assignment after initializing this.dataSource
     this.dataSource.paginator = this.paginator;
    });
  }

veuillez noter que console.log(this.sort) Imprimera toujours indéfini en raison de séquences de cycle de vie. sur ngOnInit Voir les requêtes ne sont pas définies.

donc, la question se pose; Ensuite, comment this.dataSource.sort = this.sort Travailler dans ngOnInit in MessageComponent?

la réponse est longue mais de la mettre en termes simples; parce que ce code est exécuté dans subscribe rappel. Étant donné que le code dans l'abonnement Callback est exécuté lorsque des éditions observables, une opération asynchrone se produit. et cette opération Async se produit dans un cycle de détection de changement ultérieur après un cycle où ngAfterViewInit crochet est exécuté.

vous n'obtenez pas de sortie indéfinie dans votre deuxième composant car cette instruction.log est également exécutée dans un rappel de l'abonnement. Déplacement de cette déclaration de journal hors de l'abonnement Callback n'imprimera pas non définie.

si vous placez la console.log des instructions dans ngAfterViewInit crochet, ils imprimeront tous les deux les valeurs réelles, qu'ils soient placés dans un raccordage ou non.

comme résumé;

effectuer une mission après l'initialisation this.datasource

this.dataSource= new MatTableDataSource(this.postData)
this.dataSource.sort = this.sort // make assignment after initializing 

et faites-le dans ngAfterViewInit crochet, même s'il fonctionne dans ngOnInit en raison de l'opération ASYNC.

0
ysf