Methods no longer exist when sending to/from ipcRenderer - javascript

I have the following in my render process:
class Component {
findClosestComponent(c) { /* Do stuff */ }
}
class Item extends Component {
download() {
this.myProperty = 123;
ipcRenderer.send('download-game', this);
ipcRenderer.on('download-complete', (evt, dl) => {
console.log(dl.myProperty);
dl.findClosestComponent(GameCard);
});
}
}
I then have this in my main process:
ipcMain.on('download-game', (evt, dl) => {
/* Download the file the send back the object */
evt.sender.send('download-complete', dl);
});
When I execute the download() method, it sends the current object to the main process, and then the main process sends it back. When I try to access the method findClosestComponent() it is no longer there. However, when I try to access the property myProperty it does exist and prints out.
How can I send the object to the main process then get it back and access the methods?

Electron's ipcMain and ipcRenderer modules serialize the message to JSON before sending it, so if you want to get a better idea of what actually gets sent between processes put the message through JSON.stringify(). Functions/methods and prototype chains won't make it across the process boundry, if you want that to work you'll have to implement your own serialization/deserialization scheme.

Related

Global array in next.js or react js

I want to define a global array that I can set in getserverprops and use throughout the project. Is this possible in next js?
I'm going to use this array as a cache
You can use a global variable on the server (getServerSideProps),
and
you also can use a global variable on the client (aka. the browser),
but
you can not use the same global variable on the server and the client.
Server only
If you only ever want to access that variable inside getServerSideProps,
then that is theoretically possible, but likely will cause all sorts of problems. E.g. consider a load balancer and 3 different server instances,
which have 3 different caches.
Better would be to use some "established caching technology", like a Redis DB.
Shared values
As said, you can not share a variable between server and client.
You might (as a mental model) consider getServerSideProps to be executed in a different country
on some secured server which you don't have access to, while the rest of the components (not all of them)
are executed on your computer in your browser.
So if you want to share some state between client and server, you need to create an API on the server, and communicate between client and server through this API.
If you just define a global array, that array will be created and can be used, but it will be created independently on the server and on the client, i.e. they will be two completely different variable.
my-app/global.js:
export const globalVariable = {
trace: [],
};
Then you access this variable inside the index.tsx:
my-app/pages/index.jsx:
const Home = ( props ) => {
console.log('Client: globalVariable', globalVariable);
console.log('Client: pageProps:', props);
useEffect(() => {
globalVariable.trace.push('from MyApp');
}, []);
return null;
}
export async function getServerSideProps() {
globalVariable.trace.push('from getServerSideProps');
return {
props: {
serverVariable: globalVariable,
},
}
}
Then you will have one globalVariable on the client, and a separate globalVariable on the server.
You will never see "from getServerSideProps" on the client, you will never see "from MyApp" on the server.
You can pass globalVariable from the server as props, like I did with serverVariable: globalVariable,
and that value will be available on the client, but it will be a third new variable on the client side.
You can not hope to props.serverVariable.trace.push('pushed from client to server'), that will only push
to the new client variable.

How to render a native WebComponent inside an Vue mounted app ONLY ONCE

I created a native web-component(CampusList) which will request server.
Because I put it inside an element mounted by Vue, therefor Vue will createElementof that web-component second time
Because that component will require data from server, it will send the same request twice!
Of course it should not, what should I do?
Assuming you want the fetch to only happen once (even if you have multiple instances of the element on the page) you could declare a variable inside the custom element import, but outside of the definition, and check it before you fetch. In that way the fetch will only happen the first time it's encountered e.g.:
let fetchMade = false;
class CampusList extends HTMLElement {
connectedCallback() {
if (!fetchMade) {
console.log('fetch!');
fetchMade = true;
} else {
console.log('do not fetch');
}
}
}
customElements.define('campus-list', CampusList);

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 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; e.g., 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);
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');
}

Observable / Subject loosing subscribers in Angular

I'm using a Static variable in my Class to store an initialised BehaviourSubject, so that I can provide a default, while I load the user's settings from the server.
(have put a cut down example version below)
#Injectable
export class AppSettings {
// Using a static to globalize our variable to get
// around different instances making lots of requests.
static readonly currency: Subject<string> = new BehaviorSubject('USD');
// Return a property for general consumption, but using
// a global/static variable to ensure we only call once.
get currency(): Observable<string> { return AppSettings.currency; }
loadFromServer():any {
// Broadcast the currency once we get back
// our settings data from the server.
this.someService.getSettings().subscribe(settings => {
// this is called lastly, but AppSettings.currency.observers
// seems to show as an empty array in the Inspector??
AppSettings.currency.next(settings.currency);
});
}
}
When I subscribe to it later in my code, it will run through it once (since it's a BehaviorSubject), but it won't fire after that.
export class myComponent {
public currency: string;
constructor(settings: AppSettings) {
// Called once with the default 'USD'
settings.currency.subscribe(currency => {
// only gets here once, before loadFromServer
console.log(currency);
this.currency = currency;
});
// Load from the server and have our subscription
// update our Currency property.
settings.loadFromServer();
}
}
The loadFromServer() is working exactly as expected, and the AppSettings.currency.next(settings.currency) line is being called, and after the first event. What is interesting however, is at this point, the AppSettings.currency.observables[] is empty, when it was previously filled in.
My thoughts we're initially an issue of different instances, but I'm using a static variable (have even tried a global one) to avoid different instances.
This is the current workflow...
myComponent.constructor subscribes
that subscription fires, giving the default 'USD'
the server data is loaded, and AppSettings.currency.next(settings.currency) is called
...then...nothing....
I'm expecting that at part 4 the Observer that subscribed in part 1 would be fired again, but it isn't, making my glorified Observer a constant. :(
Am I missing something?
Well I feel sheepish....
Figured out the issue was due to my import statement having the (wrong) file suffix on the file reference. So, in the myComponent file I had...
import { AppSettings } from './settings.js';
While everywhere else I have been using (the correct)
import { AppSettings } from './settings';
which was causing WebPack to compiling two versions of the class, the TypeScript and the (compiled) Javascript version, thus creating two different instances. I managed to see an AppSettings_1 somewhere, that lead me down the rabbit hole to finally gave it away.

Send Data from render process to renderer process in Electron

I am developing desktop application using Electron,
Scenario is I have 2 BrowserWindow, From FirstBrwoserWindow, I am going to SecondBrowserWindow after button click. i have instantiated SecondBrowserWindow on FirstBrwoserWindow's button click to avoid Object has been destroyed Exception.
As per Electron, if we want to send data between processes we have to use IPC. So actual problem starts here, I am creating SecondBrowserWindow object in FirstBrwoserWindow's renderer file, and for IPC i need to get SecondBrowserWindow object in main process.
How do i get SecondBrowserWindow Object in main.js and use IPC.on there????
The way I've solved this is to pass the data with ipcRenderer from the first window to the main process and then pass it with ipcMain to the second window using BrowserWindow.webContents.send().
It looks kinda like this.
Window 1
...
// Emit an ipc message with your data
ipcRenderer('your-message', { foo: 'bar' });
...
Main process
...
let window1 = new BrowserWindow(...);
let window2 = new BrowserWindow(...);
...
// when ipc message received pass it on to second window object with webContents
ipcMain.on('your-message', (event, payload) => {
window2.webContents.send('your-relayed-message', payload);
});
...
Window 2
...
// when ipc messaged received in second window do what you want with the data
ipcRenderer.on('your-relayed-message', (event, payload) => {
console.log(payload);
});
...
You can do it in more ways but what I recommend you to:
1) when you receive the input to open the 2nd BrowserWindow in the renderer, send a message to main.js
2) from main.js open the 2nd BrowserWindow so you can control it and send message to it in a cleaner way.
In this way, you can close the previous BrowserWindow without errors in communication and you have a more scalable and readable logic for N BrowserWindows.

Categories

Resources