Angular Service Worker: Where to add EventListener?

602 Views Asked by At

I am trying to build an Angular PWA which is supposed to be offline-capable. I got most of that already done, but I am struggeling on the events for the service worker: Where do I use the addEventListener(..) correctly? All tutorials and such did it in a seperate service-worker.js file which does seem very wierd to me to use JavaScript in a TypeScript enviroment. And on top of that, I would like to be able to use my Angular Services, to be able to use my already existing code to talk to the backend, which seems impossible from a standalone .js file.

I've written a Service to register a periodicSync in which I also tried to listen to the event. The periodic sync gets registered in chrome but the event will not be catched by the listener

export class SyncService{

constructor(idexedDbService: IndexedDbService, apiService: ApiService)
{}

   public RegisterSyncStuff(){
    //Works fine
    const registration : any = await navigator.serviceWorker.ready;
    try {
        await registration.periodicSync.register('download-stammdaten',{
           minInterval:  30 * 1000,
         });
     } catch {
        Console.log('no periodicSync possible')
     }
     //Does not work at all. 
     addEventListener('periodicSync', () => {
         let stuffToStore = this.apiService.getStuff();
         indexDbSerivce.StoreStuff(stuffToStore);
     })
  }

}

1

There are 1 best solutions below

3
Joosep Parts On

You might develop the worker in a TS env, but it runs as *.js file in the browser.

You build communication between the service-worker.js file and some other part of your code using event listeners and posting messages. For example:

service-worker.js

addEventListener('message', ({data}) => {
  if (data) {
    console.log('Hello from worker!')
    let newDataInArray = [data]
    postMessage(newDataInArray);
  }
});

Maybe some Service? data-service.ts

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

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

  someDataInService: Data = {data};

  constructor() {}

  sendDataToWorker() {
    runWorker(this.someDataInService);
  }

  async runWorker(data: Data) {
    if (typeof Worker !== 'undefined') {

      // Spawn a worker
      const worker = new Worker(new URL('./app.worker', import.meta.url)); 

      // Send to data to worker
      worker.postMessage(data); 

      // On return from the worker
      worker.onmessage = (dataInArray) => { 
        // do something with dataInArray?
      };
    } else {
      // Remember to handle fallback
    }
  }
}

If the worker has already been spawned, there's new need to construct a new one (unless, you want to have multiplied instances of them). To re-use the existing worker, just post a message to the instance worker.postMessage().