I am building an electron app with angular 2 in the renderer process. My main process talks to a socket server. Whenever the user is connected to this server or disconnected, I wish to show the user's status in the view.
For this, I use electron's ipc to send a message from the main to the renderer process, like this
socket.on('connect', function() {
mainWindow.webContents.send('socket-connection-status', true);
});
socket.on('disconnect', function() {
mainWindow.webContents.send('socket-connection-status', false);
});
In my view, I then have a (simplified) angular component, like this
const ipc = require('electron').ipcRenderer;
@Component({
selector: 'status-bar',
template: '{{status}}'
})
export class StatusBarComponent {
private status: string = "offline";
constructor() {
ipc.on('socket-connection-status', function(event, status) {
if (status===true) {
this.status = 'online';
} else {
this.status = 'offline';
}
console.log(status); // Successfully logs true|false
console.log(this.status); // Successfully logs online|offline
})
}
}
I successfully log the messages from main process.
The problem is that angular 2 does not 'know' electron's ipc, so change detection is not triggered for status
. I have seen several people struggling with this issue, but haven't come across a 'true' solution.
I have tried to solve it with injecting ApplicationRef
, ChangeDetectorRef
and ngZone
(ref: Triggering Angular2 change detection manually), but none of the methods provided (tick()
, detectChanges()
, run()
respectively) happened to provide a solution.
Apparently, 'within' ipc.on
I cannot reference my class' properties/methods/injectables as I run into errors: For instance, this (https://github.com/JGantner/angular2_change_detection_issue/blob/master/browser/security-level-indicator-component.ts) solution (which I find not very elegant) results in Uncaught TypeError: Cannot read property 'markForCheck' of undefined
.
Could somebody please help me out with how to make change detection work in my case?
Edit (hack):
One way I have found in which I at least get the functionality that I need/want:
status-bar.component.ts
:
const ipc = require('electron').ipcRenderer;
import { SocketStatusService } from '../services/socket-status.service';
@Component({
selector: 'status-bar',
template: '{{status}}'
})
export class StatusBarComponent {
private status: string = "offline";
status$: Subscription;
constructor(private socketStatusService: SocketStatusService, private ref: ApplicationRef) {
ipc.on('socket-connection-status', function(evt, status) {
if (status===true) {
this.service.updateSocketStatus('online');
} else {
this.service.updateSocketStatus('offline');
}
}.bind({service: socketStatusService}))
this.status$ = this.socketStatusService.socket_status$.subscribe(
status => {
this.status = status;
this.ref.tick();
}
)
}
socket-status.service.ts
:
@Injectable()
export class SocketStatusService {
private socket_status = new BehaviorSubject<string>("offline");
socket_status$ = this.socket_status.asObservable();
updateSocketStatus(status: string) {
this.socket_status.next(status);
}
}
Although this works, I have the feeling there must be a more elegant way to achieve this behavior.
Best case scenario though would be a means to set the component's class properties directly in the ipc callback and trigger change detection... So far I have not been able to get that to work, so any help would be appreciated.
(p.s. Also, I am not sure why I have to manually trigger this.ref.tick()
, which is not something I remember having had to do to trigger change detection from streams in earlier beta versions of angular 2...)