2

The code starts with an initial value in product variable, which is setted into sessionStorage. When i trigger the side-panel (child component), this receive the product.name from params in url, then this component searchs in sessionStorage and updates the product.amount value (and set it to sessionStorage).

The parent component function that i'm trying to invoke from the child component is getProductStatus(); When i update the product.amount value in the side-panel i need to update also the product object in parent component at the same time. This is what i've been trying, Thanks in advance.

Code: https://stackblitz.com/edit/angular-ivy-npo4z7?file=src%2Fapp%2Fapp.component.html

export class AppComponent {

  product: any;
  productReturned: any;

  constructor() {
    this.product = {
      name: 'foo',
      amount: 1
    };
  }

  ngOnInit() {
    this.getProductStatus();
  }

  getProductStatus(): void {
    this.productReturned = this.getStorage();
    if (this.productReturned) {
      this.product = JSON.parse(this.productReturned);
    } else {
      this.setStorage();
    }
  }

  setStorage(): void {
    sessionStorage.setItem(this.product.name, JSON.stringify(this.product));
  }

  getStorage() {
    return sessionStorage.getItem(this.product.name);
  }

  reset() {
    sessionStorage.clear();
    window.location.reload();
  }
}
sonEtLumiere
  • 4,461
  • 3
  • 8
  • 35

1 Answers1

1

You have two options for data sharing in this case. If you only need the data in your parent component:

In child.component.ts:

@Output() someEvent = new EventEmitter

someFunction(): void {
  this.someEvent.emit('Some data...')
}

In parent template:

<app-child (someEvent)="handleSomeEvent($event)"></app-child>

In parent.component.ts:

handleSomeEvent(event: any): void {
  // Do something (with the event data) or call any functions in the component
}

If you might need the data in another component aswell, you could make a service bound to the root of the application with a Subject to subscibe to in any unrelated component wherever in your application.

Service:

@Injectable()
export class DataService {

  private _data = new BehaviorSubject<SnapshotSelection>(new Data());
  private dataStore: { data: any }

  get data() {
    return this.dataStore.asObservable();
  }

  updatedDataSelection(data: Data){
    this.dataStore.data.push(data);
  }
  
}

Just pass the service in both constructors of receiving and outgoing component.

In ngOnInit() on receiving side:

subscription!: Subscription
...
dataService.data.subscribe(data => {
  // Do something when data changes
})
...
ngOnDestroy() {
  this.subscription.unsubscribe()
}

Then just use updatedDataSelection() where the changes originate.

I documented on all types of data sharing between components here:

https://github.com/H3AR7B3A7/EarlyAngularProjects/tree/master/dataSharing

For an example on the data service:

https://github.com/H3AR7B3A7/EarlyAngularProjects/tree/master/dataService

H3AR7B3A7
  • 4,366
  • 2
  • 14
  • 37
  • That's right, but in parent template i'm using and i can't send events with EventEmitter, and in the case of the data service, i know i can subscribe in parent component, but in this case how i can trigger the function that subscribes? – sonEtLumiere Jul 10 '21 at 01:53
  • I think you need to use a BehaviorSubject instead of an Observable. – H3AR7B3A7 Jul 10 '21 at 02:05
  • Can you code an example in the stackblitz link? that helps a lot – sonEtLumiere Jul 10 '21 at 02:16
  • When the slidepanel component is closed, i can emit an event with ngOnDestroy, how can i receive that event in the parent component? when the slidepanel component is destroyed, the parent component doesn't execute ngOnInit. – sonEtLumiere Jul 10 '21 at 04:47
  • You shouldn't use ngOnDestroy() for emmiting events imo ... That is meant to close resources (e.g. unsubscribing). The .next() on your behaviour subject is what makes your application aware of changes in the data you subscribed to. Or you can use onChange when @Input values change when dealing with child components. ngOnInit only runs on init. Since your parent stays alive, it won't run onInit again. – H3AR7B3A7 Jul 12 '21 at 16:27
  • 1
    In the project on my GitHub that I linked, you can find an example of emitting event to parent. The first-child emits event to parent (app-component). Your parent needs to take in event in the template and connect it to a function. Like this: (eventClick)="handleEventClick($event)" – H3AR7B3A7 Jul 12 '21 at 16:48
  • i know i can use an event emitter form child to parent, the problem i'm facing is that i'm using label so i can't use an emitter, i solved this with a router pipe in the parent component that detects the router changes, the data i need to retrieve is from sessionStorage so in this case i can trigger the parent function when the url changes. – sonEtLumiere Jul 12 '21 at 17:26
  • Hmm interesting... Why not handle both sessionstorage and a behaviorsubject in your service? Don't you create a lot of overhead with listening to routes changing? (If you console.log(), don't you get a lot of messages when session storage hasn't changed?) Just curious, I remember running in something similar a while ago. – H3AR7B3A7 Jul 12 '21 at 17:40
  • I detect the previous route with the snippet code of the winner answer of this post: https://stackoverflow.com/questions/41038970/how-to-determine-previous-page-url-in-angular . I get the previous route and i trigger the function in the parent component retrieving the data i need of sessionStorage, it works fine! – sonEtLumiere Jul 13 '21 at 03:53