SneakyShrike
SneakyShrike

Reputation: 823

Angular - Non child receiving component data is undefined when subscribed to a shared service variable which another component sets

I've been trying to share data between two unrelated components and I've used the shared service approach to this. I've looked at dozens of tutorials and tried many variations of using a service, but no matter what I do, whenever I try to console.log() the received data in the receving component the console log dispays nothing.

The service:

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class StatusBoxService 
{   
  private messageSource = new Subject<any>();
  currentMessage = this.messageSource.asObservable();

  constructor() {}
  
  changeMessage(message: any)
  {
    this.messageSource.next(message);
  }

}

The supplying component:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { StatusBoxService } from '../../services/status-box.service';

@Component({
  selector: 'app-live-summary',
  templateUrl: './live-summary.component.html',
  styleUrls: ['./live-summary.component.css']
})

export class LiveSummaryComponent implements OnInit 
{

constructor(private data: StatusBoxService) { }

  ngOnInit(): void 
  {
     this.data.changeMessage('hello world')   
  }

  ngOnDestroy(): void
  {
    //this.subscription.unsubscribe();
  }
}

The receiving component

import { Component, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { Subscription } from 'rxjs';
import { StatusBoxService } from 'src/app/services/status-box.service';
import { ConfirmActionComponent } from '../confirm-action/confirm-action.component';

@Component({
  selector: 'app-delete-status-box',
  templateUrl: './delete-status-box.component.html',
  styleUrls: ['./delete-status-box.component.css']
})
export class DeleteStatusBoxComponent implements OnInit {

  subscription!: Subscription;
  selectedDevice = '';
  testy!: any;

  constructor(private form: FormBuilder, public dialog: MatDialog, private dialogRef: MatDialogRef<DeleteStatusBoxComponent>, private data: StatusBoxService) 
  {
    //this.data.currentMessage.subscribe(param => this.testy = param) // doesn't work
    this.subscription = this.data.currentMessage.subscribe((data: any) => 
      {
        this.testy = data;
      }); // doesn't work
  }

  DeleteStatusBoxForm = this.form.group({
    selectedDevice: ['']
  });

  ngOnInit() 
  {
    console.log(this.testy);
  }

  deleteStatusBox()
  {
    this.dialog.open(ConfirmActionComponent)
    //this.dialogRef.close();
  }
}

In the receiving component I print out the testy variable which I assign to the incoming data when I subscribe to the currentMessage variable in the service.

Bur somehow when I console.log() the testy variable it displays undefined and I don't know why:

enter image description here

How Components Interact:

The app-live-summary component is a page that is part of a <router-outlet></router-outlet> with other pages. The app-live-summary contains muliple other components.

One of those components contained inside the app-live-summary page is a app-header. This app-header component contains a button that when clicked opens up the app-delete-status-box component in the form of a modal pop up box.

The app-live-summary component also has some data which I would like to pass to pass to the app-delete-status-box when the button is clicked.

Upvotes: 0

Views: 1711

Answers (2)

Can Geylan
Can Geylan

Reputation: 285

if your components used in this order:

<app-delete-status-box></app-delete-status-box>
<app-live-summary></app-live-summary>

you won't get any data since you're sending a value after app-delete-status-box component is instantiated and trying to console it on ngOnInit method which will only fire when your component is being initialized on view. Try to change the order and console the value changes on inside your subscription:

ngOnit(){
 this.subscription = this.data.currentMessage.subscribe((data: any) => 
      {
        this.testy = data;
        console.log(this.testy)
      });
}

If app-delete-status-box is a dialog component, you can use dialog.open(yourComponent, data) method to send that value (call the service method there to fetch the values). More info on dialog here: https://material.angular.io/components/dialog/overview

Upvotes: 2

sky6
sky6

Reputation: 36

I think that the component has not a good loading sequence. If you move "console.log" in

this.subscription = this.data.currentMessage.subscribe((data: any) => 
  {
    this.testy = data;
    console.log(this.testy);
  });

It's works ?

In view, you can use AsyncPipe to get result with observable.

{{ testy$ | async }}

Upvotes: 0

Related Questions