'Electron.js I can't do the Button action

follow my source code, does anyone know more about Electron around here? I'm starting to study now and I'm trying to create an App that will update some files through an FTP, my problem initially I put a button on the acc.html page, but I can't do its action, I've looked for several examples but with none I can do , to work, it doesn't also arrive in the script that is defined inside the acc.html.

renderer.js

// include the ipc module to communicate with main process.
const ipcRenderer = require('electron').ipcRenderer; 

console.log("Chamou O Renderer.js");
 
document.getElementById('buttonBaixarACCCustoms').open = () => {
    //ipcRenderer.send('openFile', {})
    console.log("Entrou No IPCRender");
    ipcRenderer.send("btnclick", arg); // ipcRender.send will pass the information to main process
  }


/*
const btnclick = document.getElementById('buttonBaixarACCCustoms');
btnclick.addEventListener('onclick', function () {
    console.log("Entrou No IPCRender");
    var arg ="secondparam";
 
   //send the info to main process . we can pass any arguments as second param.
    ipcRenderer.send("btnclick", arg); // ipcRender.send will pass the information to main process
});
*/

app.js

const {app, BrowserWindow, ipcMain, } = require('electron');
const url = require("url");
const path = require("path");
const ftp = require("basic-ftp");

let appWindow;

function initWindow() {
  appWindow = new BrowserWindow({
    width: 1000,
    height: 800,
    webPreferences: {
      contextIsolation: false,
      nodeIntegration: true,
      webviewTag: true
    }
  })

  // Electron Build Path
  appWindow.loadURL('file://' + __dirname + '/electron-tabs.html');
  /*
  appWindow.loadURL(
    url.format({
      pathname: path.join(__dirname, `/dist/index.html`),
      protocol: "file:",
      slashes: true
    })
  );
  */

  // Initialize the DevTools.
  appWindow.webContents.openDevTools();

  appWindow.on('ready-to-show', function () {
    appWindow.show();
    appWindow.focus();
  });

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

app.on('ready', initWindow)

// Close when all windows are closed.
app.on('window-all-closed', function () {

  // On macOS specific close process
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', function () {
  if (win === null) {
    initWindow();
    example();
  }
})

example()

async function example() {

    console.log("Entrou No Example...");

    const client = new ftp.Client()
    client.ftp.verbose = true
    try {
        await client.access({
            host: "127.0.0.1",
            user: "topgunav",
            password: "topgunav",
            secure: false
        })
        debugger;
        //console.log(await client.list());
        //await client.uploadFrom("README.md", "README_FTP.md")
        //await client.downloadTo("README_COPY.md", "README_FTP.md")
    }
    catch(err) {
        console.log(err)
    }
    client.close()
}
//ipcMain.on will receive the “btnclick” info from renderprocess 
ipcMain.on("btnclick", function (event, arg) {
  console.log("Chegou Aqui No IPCMain");

  //create new window
  /*
  var newWindow        = new BrowserWindow({ width: 450, height: 300, show: 
                                        false,webPreferences: {webSecurity: false,plugins:
                                        true,nodeIntegration: false} });  // create a new window

  var facebookURL     =  "https://www.facebook.com"; // loading an external url. We can
                                        load our own another html file , like how we load index.html earlier

  newWindow.loadURL(facebookURL);
  newWindow.show();
  */

 // inform the render process that the assigned task finished. Show a message in html
// event.sender.send in ipcMain will return the reply to renderprocess
 //event.sender.send("btnclick-task-finished", "yes"); 
});

acc.html

<!DOCTYPE html>
<html>

<head>
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body style="margin:0">

    <h1 style="text-align: center;">Sicronização De CarSet's</h1>

    <div class="mb-3">
        <label for="caminhoACCCustoms" class="form-label">Informe O Caminho Da Pasta Customs</label>
        <input type="text" class="form-control form-control-lg" type="text" id="caminhoACCCustoms" placeholder="C:\Users\eders\OneDrive\Documentos\Assetto Corsa Competizione\Customs">
    </div>

    <select class="form-select form-select-lg mb-3" aria-label=".form-select-lg example">
        <option selected>Informe A Temporada Que Deseja Sicronizar</option>
        <option value="1">T1</option>
        <option value="2">T2</option>
        <option value="3">T4</option>
        <option value="3">T5</option>  
    </select>

    <button type="button" class="btn btn-primary btn-lg" id="buttonBaixarACCCustoms">Baixar</button>

</body>

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>

<script src="../../renderer.js"></script>

</html>

electron-tabs.html

<!DOCTYPE html>
<html>

<head>
  <title>SuperSync</title>
  <link rel="stylesheet" href="./node_modules/electron-tabs/electron-tabs.css">
</head>
<body style="margin:0">

<div class="etabs-tabgroup">
  <div class="etabs-tabs"></div>
  <div class="etabs-buttons"></div>
</div>
<div class="etabs-views"></div>

</body>

<script src="./renderer.js"></script>

<script>

  const TabGroup = require('electron-tabs');

  let tabGroup = new TabGroup();
 
  tabGroup.addTab({
    title: "Assetto Corsa Competizione",
    src: "./src/acc/acc.html",
    visible: true,
    active: true
  });

</script>


Solution 1:[1]

Understanding and implementing Inter-Process Communication can be tricky. You need a good understanding of the Process Model and Context Isolation.

In the below code I have greatly simplified your questions code to show only what is required to get a working IPC process.


The purpose of this preload.js script is to define 'channel names' and the implementation of IPC between the main process and render process(es).

This preload.js script can be included in all your window creation scripts. IE: webPreferences: { preload: 'preload.js' }.

preload.js (main process)

// Import the necessary Electron components.
const contextBridge = require('electron').contextBridge;
const ipcRenderer = require('electron').ipcRenderer;

// White-listed channels.
const ipc = {
    'render': {
        // From render to main.
        'send': [
            'buttonClick' // Channel name
        ],
        // From main to render.
        'receive': [],
        // From render to main and back again.
        'sendReceive': []
    }
};

// Exposed protected methods in the render process.
contextBridge.exposeInMainWorld(
    // Allowed 'ipcRenderer' methods.
    'ipcRender', {
        // From render to main.
        send: (channel, args) => {
            let validChannels = ipc.render.send;
            if (validChannels.includes(channel)) {
                ipcRenderer.send(channel, args);
            }
        },
        // From main to render.
        receive: (channel, listener) => {
            let validChannels = ipc.render.receive;
            if (validChannels.includes(channel)) {
                // Deliberately strip event as it includes `sender`.
                ipcRenderer.on(channel, (event, ...args) => listener(...args));
            }
        },
        // From render to main and back again.
        invoke: (channel, args) => {
            let validChannels = ipc.render.sendReceive;
            if (validChannels.includes(channel)) {
                return ipcRenderer.invoke(channel, args);
            }
        }
    }
);

This preload.js script can be used in your main process and render process(es) as shown below.

/**
 * Render --> Main
 * ---------------
 * Render:  window.ipcRender.send('channel', data); // Data is optional.
 * Main:    electronIpcMain.on('channel', (event, data) => { methodName(data); })
 *
 * Main --> Render
 * ---------------
 * Main:    windowName.webContents.send('channel', data); // Data is optional.
 * Render:  window.ipcRender.receive('channel', (data) => { methodName(data); });
 *
 * Render --> Main (Value) --> Render
 * ----------------------------------
 * Render:  window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
 * Main:    electronIpcMain.handle('channel', (event, data) => { return someMethod(data); });
 *
 * Render --> Main (Promise) --> Render
 * ------------------------------------
 * Render:  window.ipcRender.invoke('channel', data).then((result) => { methodName(result); });
 * Main:    electronIpcMain.handle('channel', async (event, data) => {
 *              return await promiseFunctionName(data)
 *                  .then(() => { return result; })
 *          });
 */

During window creation make sure to include your preload.js script. Then listen for a message on the 'buttonClick' channel.

main.js (main process)

const electronApp = require('electron').app;
const electronBrowserWindow = require('electron').BrowserWindow;
const electronIpcMain = require('electron').ipcMain;

const nodePath = require("path");

// Prevent garbage collection
let window;

function createWindow() {
    const window = new electronBrowserWindow({
        x: 0,
        y: 0,
        width: 800,
        height: 600,
        show: false,
        webPreferences: {
            nodeIntegration: false,
            contextIsolation: true,
            preload: nodePath.join(__dirname, 'preload.js') // Include the preload.js script
        }
    });

    window.loadFile('index.html')
        .then(() => { window.show(); });

    return window;
}

electronApp.on('ready', () => {
    window = createWindow();
});

electronApp.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        electronApp.quit();
    }
});

electronApp.on('activate', () => {
    if (electronBrowserWindow.getAllWindows().length === 0) {
        createWindow();
    }
});

// Listen for a message on the 'buttonClick' channel
electronIpcMain.on('buttonClick', (event, data) => {
    console.log(data); // Testing
})

Lastly, listen for a click event on the button, gather the data and send it via the correct IPC channel (name) to the main process for processing.

index.html (render process)

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

    <body>
        <h1>Sicronização De CarSet's</h1>

        <label for="textField">Informe O Caminho Da Pasta Customs</label>
        <input id="textField" type="text" placeholder="C:\Custom\Path"><br>

        <label for="selectField">Informe A Temporada Que Deseja Sicronizar</label>
        <select id="selectField">
            <option value="1">T1</option>
            <option value="2">T2</option>
            <option value="3">T3</option>
            <option value="4">T4</option>
        </select><br>

        <button id="button" type="button">Baixar</button>
    </body>

    <script>
        document.getElementById('button').addEventListener('click', () => {
            let data = {
                textField: document.getElementById('textField').value,
                selectField: document.getElementById('selectField').value
            }

            console.log(data); // Testing

            window.ipcRender.send('buttonClick', data);
        });
    </script>
</html>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 midnight-coding