简体   繁体   中英

Pass data between components in a new tab

I have an object in one component and I want to pass it to another component. The problem is that this other component will open in a new tab.

I tried to use the data service strategy, but when the tab opens, the data service object comes undefined.

I thought about using the querys params and passing in the url. But the object is very complex

My data service:

  @Injectable({providedIn: 'root'})
  export class DataService {

   private anime: Anime;

   constructor() { }

   setAnime(anime: Anime) {
    this.anime = anime;
   }
   getAnime() {
    return this.anime;
   }
 }

Setting object in data service:

goToDetailsByService(anime: Anime) {
   this.dataService.setAnime(anime);
   //this.router.navigateByUrl('/details');
   window.open('/details');
}

Getting the anime object via service data:

ngOnInit(): void {
  console.log(this.dataService.getAnime());
  this.anime = this.dataService.getAnime()

}

When accessing the details component via navigate router works

I think the easiest way to do it would be to use the browsers localStorage since that will keep the applicaton state between tabs. When you open a new tab the two web pages are seperate and the state doesn't carry over.

So using localStorage you can do..

SET

goToDetailsByService(anime: Anime) {
  localStorage.setItem('anime', JSON.stringify(anime));
  window.open('/details');
}

GET

ngOnInit(): void {
  this.anime = JSON.parse(localStorage.getItem('anime'));

  // here you can choose to keep it in the localStorage or remove it as shown below
  localStorage.removeItem('anime');
}

I think there are two ways to do it. The first one is localStorage , the second one is PostMessage

localStorage

we can use localstorage because storage can be read across windows, and there is a storage event fire when you write something to storage.

Here is the code example.

// parent window
localStorage.setItem("EVENT.PUB", JSON.stringify(anime));

// child widnow
window.addEventListener('storage', function(event) {
  console.log(event);
  const anime = JSON.parse(event.newValue);
}, false);

postMessage

The window.postMessage() method safely enables communication between Window objects; eg, between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.

Here is the code example.

// parent window
const detailPage = window.open('/details');
detailPage.postMessage(anime, '*');
// important notice: anime should be object that can be serialize
// otherwise error will happen when execute this function.


// child window
window.addEventListener('message', (event) => {
  // get out the message
  console.log(event.data);
  // and you can even send message back to parent window too.
  event.source.postMessage('Got it!',  event.origin);
}, false);

You need to use a BehaviorSubject to keep the last value.

Example:

@Injectable({providedIn: 'root'})
  export class DataService {

   private anime$ = new BehaviorSubject<Anime>();

   constructor() { }

   setAnime(anime: Anime) {
    this.anime$.next(anime);
   }
   getAnime() {
    return this.anime$;
   }
 }

Now there are to ways to get the anime value. One with an observable (it will triggered every time when the value changes).

this.dataService.getAnime().subscribe(anime => {this.anime = anime});

Or just getting the value directly:

this.anime = this.dataService.getAnime().value; 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM