1

I'm trying send data from an Angular component to another Angular component.

I've managed to do it through sessionStorage but I understand that it's not the best practise as it should only contain data relative to the user's identification, logging etc.

From several tutorials I've seen, I must pass the data through the html through an EventEmitter. As seen in all those technics Sharing Data between Angular Components - Four Methods

However what I'd ideally like to do is pass data from the parent component to the child component, through the ts components as to be able to manipulate the data directly there and then decide what to do with it in the parent html.

Is there a way of doing this?

Any help would be most apreciated. Thanks!

Here is my Parent component:

import { Component, OnInit, Output } from '@angular/core';
import { CloudinaryModule, CloudinaryConfiguration } from '@cloudinary/angular-5.x';
import { Cloudinary } from 'cloudinary-core';
import { EventEmitter } from '@angular/core';

@Component({
  selector: 'app-eacloudinary',
  templateUrl: './eacloudinary.component.html',
  styleUrls: ['./eacloudinary.component.scss']
})
export class EacloudinaryComponent implements OnInit {
  title = "CloudinaryTesting";
  private widget:any = null;

  // imagesList to stock uploaded Images URL
  imagesList: any;

  @Output() public found = new EventEmitter<any>(); // emit event for other comp

  constructor() { }

  ngOnInit(): void {
    // init of the imagesList
    this.imagesList = [];

    console.log("initialized");
    (window as any).cloudinary.createMediaLibrary(
      {
        cloud_name: "cloud_name",
        api_key: "0000",
        button_class: "myBtn",
        username: "username",
        button_caption: "Select Image or Video"
      },
      {
        insertHandler: function(data) {
          data.assets.forEach(asset => {
            console.log("Inserted asset:", JSON.stringify(asset, null, 2));
          });
        }
      },
      "#open-btn"
    );

    this.widget = (window as any).cloudinary.createUploadWidget(
      {
        cloudName: "cloud_name",
        uploadPreset: "testing"
      },
      (error, result) => {
        console.log(error);
        console.log("EAcloudinary 44", result);
        if (result.event=="success") {
          sessionStorage.setItem('imagesURLS', result['info']['url']); // sotcking the url in sessionStorage
          let imagesList = [];
          imagesList.push(result['info']['url']); // stocking of the URLS into the imagesList
          imagesList = [...imagesList];
          this.found.emit(imagesList); // here emit event
         }
      }
    );
  }
  onOpenUpload($event) {
    this.widget.open();
    console.log("Open upload button is clicked!", $event);
  }

}

Here is my Parent html:

<div>
  <h1>
    Welcome to {{ title }}!
  </h1>

  <h2>Media Library</h2>
  <div id="open-btn"></div>
  <h2>Upload Widget</h2>
  <div>
    <button
      id="upload_widget"
      (click)="onOpenUpload($event)"
      class="cloudinary-button"
    >
      Upload files
    </button>
  </div>
</div>

Here is my Child component:

import { Component, OnInit, Input } from '@angular/core';
...
import { Router } from '@angular/router';
import { FormBuilder, FormGroup } from '@angular/forms';

@Component({
  selector: 'app-details',
  templateUrl: './details.component.html',
  styleUrls: ['./details.component.scss']
})
export class UserComponent implements OnInit {

  readonly ROOT_URL = 'http://127.0.0.1:8000';

...

  @Input() public imagesListURLS : Array <any> = [];
  imagesListData = [];

  constructor(
    ...
  ) {
    ...
  }

  ngOnInit(): void {
    ...
    }

  ...

  // bind imagesList
  getImagesList(imagesListURLS: any) {
    this.imagesListData = imagesListURLS
  }
  ...
}

1 Answer 1

3

When there is multi-level component communication required, it is usually done through a service containing a Subject variable whose data is updated by one or more sources and also subscribed by one or more sources. You may google "Event Bus Service" or "Observable Service" to read about it more.

Take an example of a scenario where there is a flag in the App Component that enables or disables the display of something. This flag may be updated by a very inner level component, so to communicate between the inner level component and the App Component, we shall use a service that would look somewhat like this:

@Injectable({providedIn: 'root'})
export class DataCommunicationService {
    private _displayFlag: Subject<boolean>;
    
    constructor() {
        this._displayFlag = new BehaviorSubject(false);
    }
    
    updateFlag(value: boolean): void {
        this._displayFlag.next(value);
    }

    get displayFlag(): Observable<boolean> {
        return this._displayFlag.asObservable();
    }
}

Now, you inject this service in both your App Component and the inner child component. The inner child component, based on some condition shall update the flag using a statement like this:

this.dataCommunicationService.updateFlag(true);

The App Component needs to subscribe for any value changes in the following way:

this.dataCommunicationService.displayFlag.subscribe(flag => this.showObjectFlag = flag);
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the swift reply. Will test it and come back to you tomorrow either with more questions or to validate your answer. I'm just not sure about the updateFlag function. Can I pass it something else than a boolean? Not comfortable with how next() passes or inserts data into the variable _displayFlag.
You can pass any kind of object, not just boolean.
Have tested your solution and it works, really like plug and play and understand better the use of BehaviorSubject and next(). Thanks a lot.
There are other variations of Subjects too, you may go through them, they come in handy a lot especially for use cases like the one you have mentioned.
Indeed, I was able to use observables and subscribe to them, like creating a service to make http requests to the backend when needed, but had no idea a Subject was a specific type of those. Very convenient

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.