What's the proper way to handle forms in Elect

2020-07-01 02:40发布

The form html and submit event is part of the "renderer". The submitted data should be available in the main process. What's the proper way to submit the form and make that data accessible in main.js ?

Should I simply use the "remote" module to pass the data to a function from main.js or is there a better approach?

3条回答
Ridiculous、
2楼-- · 2020-07-01 03:21

Remote is great way to share data. Using global variables and share them with other pages of our electron application. So, based on the following IPC approach, I was able to manage it this way :

1) Add this code in the main.js file :

   global.MyGlobalObject = {
      variable_1: '12345'
   }

2) Use this on your 1st page to update global variable value :

require('electron').remote.getGlobal('MyGlobalObject').variable_1= '4567'

3) Lastly, use something like this on your 2nd page where you'll access the modified global variable and print it :

console.log(require('electron').remote.getGlobal('MyGlobalObject').variable_1)

You can find the same thing in electron's documentation.

查看更多
祖国的老花朵
3楼-- · 2020-07-01 03:23

There are several variations on how to do this, but all are via IPC

IPC (inter process communication) is the only way to get data from the render process to the main process, and is event driven. The way this works is that you can use custom defined events which the process listens for and returns something when that event happens.

The example stated by @Adam Eri is a variation on the ipcMain example found in the documentation, but this method is not one size fits all.

The reason for saying that is the matter can quickly become complicated if you are trying to send events via the menu (which typically runs on the main process), or via components through a front end framework like Vue or Angular.

I will give a few examples:

Using Remote with WebContents

To your point, yes you can use electron remote, but for the purposes of forms it is not the recommended approach. Based on the documentation, the point of remote is to 

Use main process modules from the renderer process

tl:dr -This process can cause deadlocks due to its synchronous nature, can cause event object leaks (due to garbage collection), and leads to unexpected results with callbacks.

Further explanation can be had from the documentation but ultimately this is set for using items like dialog and menu in the render process.

index.js (main process)

const { app, BrowserWindow, ipcMain } = require('electron');
const path = require ('path');
const fs = require('fs');
const os = require('os');

let window;

function createWindow(){
    window = new BrowserWindow({
        show: false
    });

    window.loadURL(`file://${__dirname}/index.html`);
    window.once('ready-to-show', function (){
        window.show();
    });

    window.webContents.openDevTools();

    let contents = window.webContents;

    window.on('closed', function() {
        window = null;
    });
}

exports.handleForm = function handleForm(targetWindow, firstname) {
    console.log("this is the firstname from the form ->", firstname)
    targetWindow.webContents.send('form-received', "we got it");
};

app.on('ready', function(){
    createWindow();
});

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Electron App</title>
    </head>

    <body>

        <form action="#" id="ipcForm2">
            First name:<br>
            <input type="text" name="firstname" id="firstname" value="John">
            <br>
            Last name:<br>
            <input type="text" name="lastname" id="lastname" value="Smith">
            <br><br>
            <input id="submit" type="submit" value="submit">
        </form>

        <p id="response"></p>

        <script src='renderFile.js'></script>
    </body>
</html>

renderFile.js (Render Process)

const { remote, ipcRenderer } = require('electron');
const { handleForm} = remote.require('./index');
const currentWindow = remote.getCurrentWindow();

const submitFormButton = document.querySelector("#ipcForm2");
const responseParagraph = document.getElementById('response')

submitFormButton.addEventListener("submit", function(event){
        event.preventDefault();   // stop the form from submitting
        let firstname = document.getElementById("firstname").value;
        handleForm(currentWindow, firstname)
});

ipcRenderer.on('form-received', function(event, args){
    responseParagraph.innerHTML = args
    /*
        you could choose to submit the form here after the main process completes
        and use this as a processing step
    */
});

Traditional IPC

index.js (Main Process)

const { app, BrowserWindow, ipcMain } = require('electron');
const path = require ('path');
const fs = require('fs');
const os = require('os');

let window;

function createWindow(){
    window = new BrowserWindow({
        show: false
    });

    window.loadURL(`file://${__dirname}/index.html`);
    window.once('ready-to-show', function (){
        window.show();
    });

    window.webContents.openDevTools();

    let contents = window.webContents;

    window.on('closed', function() {
        window = null;
    });
}

ipcMain.on('form-submission', function (event, firstname) {
    console.log("this is the firstname from the form ->", firstname)
});

app.on('ready', function(){
    createWindow();
});

index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Electron App</title>
    </head>

    <body>

        <form name="ipcForm" onSubmit="JavaScript:sendForm(event)">
            First name:<br>
            <input type="text" name="firstname" id="firstname" value="John">
            <br>
            Last name:<br>
            <input type="text" name="lastname" id="lastname" value="Smith">
            <br><br>
            <input type="submit" value="Submit">
        </form>

        <script src='renderFile.js'></script>
    </body>
</html>

renderFile.js (Render Process)

const ipcRenderer = require('electron').ipcRenderer;

function sendForm(event) {
    event.preventDefault() // stop the form from submitting
    let firstname = document.getElementById("firstname").value;
    ipcRenderer.send('form-submission', firstname)
}

Using WebContents

A possible third option is webContents.executeJavascript to access the renderer process from the main process. This explanation from the remote documentation section.

Summary

As you can see, there are a few options on how to handle forms with Electron. So long as you use IPC, you should be fine; its just how you use it that can get you into trouble. I have shown plain javascript options for handling forms, but there are countless ways to do so. When you bring a front end framework into the mix, it gets even more interesting.

I personally use the traditional IPC approach when I can.

Hope that clears things up for you!

查看更多
叼着烟拽天下
4楼-- · 2020-07-01 03:39

We use a service (Angular) to process form data in a window. Then notify the remote, if needed.


From your renderer you can send data to the ipc, then in your main.js you catch this event and the passed form data:

// renderer.js
let ipcRenderer = require('electron').ipcRenderer;
ipcRenderer.send('submitForm', formData);

// main.js
ipcMain.on('submitForm', function(event, data) {
   // Access form data here
});

You can also send messages back to the renderer from the main.js.

Either sync:

// main.js
ipcMain.on('submitForm', function(event, data) {
   // Access form data here
   event.returnValue = {"any": "value"};
});

Or async:

// main.js
ipcMain.on('submitForm', function(event, data) {
   // Access form data here
   event.sender.send('formSubmissionResults', results);
});

// renderer.js
ipcRenderer.on('formSubmissionResults', function(event, args) {
   let results = args.body;
});
查看更多
登录 后发表回答