4

In Angular 8 I want to implement an Angular-Material Modal-Dialog. Upon clicking on a user image, the user data should be displayed in the modal. I am unable to pass the dynamic data of the observable from the Profile component to the Profile-Modal component. For testing, I subscribed to the observable in the ngOnInit() of Profile.component.ts, the array of data objects is console-logged properly. If I use the same subscription in openDialog() which serves to open the Modal-Dialog, I get this error message: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays. at NgForOf.ngDoCheck

profile.component.ts: (in profile.component.html everything works properly, *ngFor="let member of members" works correct and with interpolation I get the data, i.e. {{member.name }})

import { Component, OnInit } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';
import { Observable } from 'rxjs';

import { MatDialog } from '@angular/material';
import { ProfileModalComponent } from '../profile-modal/profile-modal.component';

@Component({
  selector: 'app-profile',
  templateUrl: './profile.component.html',
  styleUrls: ['./profile.component.css']
})
export class ProfileComponent implements OnInit {
  observableData: observableData[] = [];
  members: Observable<any[]>;

  constructor(db: AngularFirestore,
              public dialog: MatDialog) {
    this.members = db.collection('members').valueChanges();
  }

  openDialog(): void {
    let observableData = this.members.subscribe(members => members);
    this.dialog.open(ProfileModalComponent, {
      width: '80%',
      height: '80%',
      data: {data: observableData}
    });
  }
  // logs the array with the objects
  ngOnInit() {
    const members = this.members.subscribe(
      member => console.log(member)
    )
  }
}

profile-modal.component.ts:

import { Component, Inject, Input } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';

@Component({
  selector: 'app-profile-modal',
  templateUrl: 'profile-modal.component.html',
  styleUrls: ['profile-modal.component.css']
})
export class ProfileModalComponent {
  constructor(public dialogRef: MatDialogRef<ProfileModalComponent>,
              @Inject(MAT_DIALOG_DATA) public data: any) {}

  onNoClick(): void {
    this.dialogRef.close();
  }
}
maraxai
  • 135
  • 1
  • 3
  • 14

3 Answers3

1

I think you can open modal after you receive the data like this:

openDialog(): void {
   this.members.subscribe(members => {
      this.dialog.open(ProfileModalComponent, {
        width: '80%',
        height: '80%',
        data: {data: members }
      });
   });
 }

Try this it can solve the problem.

  • Thanks for your advice but it does not fix the problem. With this code, the modal-dialog does not even open. – maraxai Nov 12 '19 at 19:54
  • Ok, but do you receive the data (members) ? Maybe back-end sends an error – Arsen Galloghlyan Nov 13 '19 at 07:08
  • I get an error message with your solution: ` ProfileComponent.ngfactory.js? [sm]:1 ERROR TypeError: this.members.subscribe is not a function at ProfileComponent.openDialog` – maraxai Nov 13 '19 at 09:27
  • I know this is old, but another core issue with this is that it can lead to a memory leak. Should openDialog be called multiple times, multiple subscriptions will be created and won't be disposed of in memory – jarodsmk Oct 18 '22 at 05:37
1

If using async pipe is allowed for ngFor, use it. Maybe this way works:

ngFor="let member of data | async"
R. Nourmandi
  • 157
  • 12
0

UPDATE
After taking a look on your stackblitz I created a fix for your problem here https://stackblitz.com/edit/angular-vwhas1


The problem is in your *ngFor. It should be let member of data.data.
Because you have assigned the observable like this:
data: {data: observableData} , it means that in your modal/dialog component, you can access it by data.data

Your fixed code

<fa-icon id="closeModal" class="icon" [icon]="faTimes" (click)="onNoClick()">
</fa-icon> 
<div class="container"> 
 <h1 mat-dialog-title>Profil</h1> 
 <div mat-dialog-content> 
  <div class="member" *ngFor="let member of data.data"> 
   <span>NAME: </span> 
   <span>{{member.name}}</span>
  </div> 
 </div> 
</div>
Bogdan B
  • 846
  • 9
  • 23
  • With this code I get the error: `Error: InvalidPipeArgument: '[object Object],[object Object],...' for pipe 'AsyncPipe' at invalidPipeArgumentError` If I remove the _async_ pipe, I get the complete list of all objects. – maraxai Nov 13 '19 at 09:20
  • But `{{ member.name }}` should only return one object and not all. – maraxai Nov 13 '19 at 09:32
  • Try changing `let observableData = this.members.subscribe(members=>members);` to `let observableData = this.members.subscribe()` . If that doesn't work i can only think that the data source does not contains an array, but an object that contains an array. I'm waiting for your reply. – Bogdan B Nov 13 '19 at 09:35
  • No, it is not working. But I have to admit that I changed the code slightly, in the meantime. Could I show you step-by-step what I did, starting with the db structure, the service, interface and modal? – maraxai Nov 13 '19 at 10:22
  • Can you reproduce the problem in a stackblitz? It's hard to debug it this way. – Bogdan B Nov 13 '19 at 16:12
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/202287/discussion-between-maraxai-and-bogdan-b). – maraxai Nov 13 '19 at 20:46