web-dev-qa-db-fra.com

Quelle est la bonne façon de gérer les formulaires dans Electron?

Le formulaire html et l'événement submit font partie du "moteur de rendu". Les données soumises devraient être disponibles dans le processus principal. Quelle est la bonne façon de soumettre le formulaire et de rendre ces données accessibles dans main.js?

Dois-je simplement utiliser le module "distant" pour transmettre les données à une fonction de main.js ou existe-t-il une meilleure approche?

24
Elfy

Nous utilisons un service (angulaire) pour traiter les données du formulaire dans une fenêtre. Informez ensuite le remote, si nécessaire.


Depuis votre renderer, vous pouvez envoyer des données vers le ipc, puis dans votre main.js vous interceptez cet événement et les données de formulaire transmises:

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

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

Vous pouvez également renvoyer des messages vers le renderer depuis le main.js.

Soit sync:

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

Ou 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;
});
11
Adam Eri

Il existe plusieurs variantes sur la façon de procéder, mais toutes se font via IPC .

IPC (communication inter-processus) est le seul moyen d'obtenir des données du processus de rendu vers le processus principal et est piloté par les événements. La façon dont cela fonctionne est que vous pouvez utiliser des événements définis personnalisés que le processus écoute et renvoie quelque chose lorsque cet événement se produit.

L'exemple indiqué par @Adam Eri est une variation de exemple ipcMain trouvé dans la documentation, mais cette méthode n'est pas universelle.

La raison pour laquelle c'est le cas peut rapidement devenir compliquée si vous essayez d'envoyer des événements via le menu (qui s'exécute généralement sur le processus principal), ou via des composants via un framework frontal comme Vue = ou angulaire.

Je vais donner quelques exemples:

Utilisation de Remote avec WebContents

Pour votre point, oui, vous pouvez utiliser electron remote , mais pour les besoins des formes ce n'est pas l'approche recommandée . Sur la base de la documentation, le point de la télécommande est de

Utiliser les modules de processus principaux du processus de rendu

tl: dr - Ce processus peut provoquer des interblocages en raison de sa nature synchrone, peut provoquer des fuites d'objets d'événement (en raison de la récupération de place) et conduit à des résultats inattendus avec des rappels.

Des explications supplémentaires peuvent être obtenues à partir de la documentation, mais en fin de compte, elles sont définies pour l'utilisation d'éléments comme dialog et menu dans le processus de rendu.

index.js (processus principal)

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 (processus de rendu)

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
    */
});

IPC traditionnel

index.js (processus principal)

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 (processus de rendu)

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)
}

Utilisation de WebContents

Une troisième option possible est webContents.executeJavascript pour accéder au processus de rendu à partir du processus principal. Cette explication de la section de documentation remote .

Résumé

Comme vous pouvez le voir, il existe quelques options sur la façon de gérer les formulaires avec Electron. Tant que vous utilisez IPC, vous devriez être bien; c'est juste la façon dont vous l'utilisez qui peut vous causer des ennuis. J'ai montré des options javascript simples pour gérer les formulaires, mais il existe d'innombrables façons de le faire. Lorsque vous apportez un framework frontal dans le mix, cela devient encore plus intéressant.

Personnellement, j'utilise l'approche traditionnelle IPC quand je le peux).

J'espère que les choses sont clairs pour toi!

7
unseen_damage