Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change Detection works intermittently when receiving data from Electron Container IPC Channel

I have an application that is listening for incoming data from an IPC Renderer Channel. Here is my setup:

container that sends data to angular app (mainWindow):

mainWindow.loadURL('http://www.myangularapp.com') //where the angular app lives (example url).
mainWindow.webContents.on('did-finish-load', () => {
      const data = { name: "John Doe", address: "123 Main St", city: "NY"}
      mainWindow.webContents.send('data-from-container', data)
        }
    })

angular app:

constructor(
    private store: Store<fromStore.AppState>,
    private cd: ChangeDetectorRef,
    private zone: NgZone,
  ) {}

  ngOnInit() {
this.isLoading = true;
    if (this.electronService.ipcRenderer) {
      this.electronService.ipcRenderer.on('data-from-container', (event, data) => {
        this.zone.run(() => {
          if(data){
            setTimeout(() => {
              console.log(data) // verified data is always received
              this.formData = data; // property that form uses to populate data in the dom
              this.prepopulateForm(data) // method that places incoming data in ngrx store
            }, 1000)
          }
        })
      })
    }

    this.store.select('containerData').subscribe(data => {
        setTimeout(()=> {
          console.log(data) // data is always being set in ngrx
          this.isLoading = false
        }, 5000);
    })

  }

Everytime the IPC Channel emits the 'data-from-container' event, the data is always getting received from my OnInit call, but the data doesn't always get set in my form! The pattern that i've noticed is typically that the data does not prepopulate the form when the angular app first launches inside the container, after the initial launch, every subsequent time the app is launched, the data appears.

I've tried using ngZone, setTimeout, and detectChange methods to trigger Change Detection so the Angular App can detect the newly set formData, but its not consistently prepopulating the form. Any suggestions on how to fix this?

like image 605
Kode_12 Avatar asked Jul 15 '19 23:07

Kode_12


1 Answers

I have a very basic knowledge of electron, so i'll try to show you the idea. For me, your problem comes from the initialization of the view. You're not loosing events because you can see them in the console but not in the view, which enforces my guesses.

As shown in your code, your are sending only one event (I suppose it's only for testing raison) and we want to show it when the view is rendered.

In your component add a subject which informes us that the view is initialized, like:

import { Subject, combineLatest, fromEvent } from 'rxjs';

viewInitialized$ = new Subject();

...

ngAfterViewInit() {
 this.viewInitialized$.next();
}

...

Now we can wait the two emissions to come, one from the ipcRenderer and the other from viewInitialized$by using combineLatest operator.

Before that, we have to convert the ipcRenderer to an Observable. From this SO response we can do fromEvent(ipcRenderer,'data-from-container'). If it does not work we can use another subject that emits events each time we receive something in ipcRenderer.on(), the second solution requires ngZone.


ngOnInit() {
...

const containerData$ = fromEvent(this.electronService.ipcRenderer, 'data-from-container');
this.subscription = combineLatest(containerData$, this.viewInitialized$).subscribe(combined => {
  const data = combined[0];
  this.formData = data;
  this.prepopulateForm(data) 
})

...
}

ngOnDestroy() {
  this.subscription.unsubscribe();
}

Hope this helps.

like image 58
bubbles Avatar answered Nov 15 '22 16:11

bubbles