Home > OS >  querySelector or addEventListener is not working with electron in html
querySelector or addEventListener is not working with electron in html

Time:11-05

I've started a desktop project with electron. But my button is not working, no any error. Here is the HTML code:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="assets/bootstrap.min.css">
</head>
<body>
  <h1>gangway app</h1>
  <button  id="sendBtn">Send</button>
  <script>
    const electron = require("electron")
    const {ipcRenderer} = electron

    let sendBtn = document.querySelector("#sendBtn");
    sendBtn.addEventListener('click',()=>{
      alert("Alert")
      ipcRenderer.send("key","Gangway Test")
    })
  </script>
</body>
</html>

So when I start my project I have just one button and it's not working. I dont get any alert. Also I try to post data with ipcRenderer and catch it in main.js with ipcMain but also no any data came. Do I have something wrong with button id?

CodePudding user response:

You cannot just use require("electron") inside an HTML file, that has been deprecated. You must have been following an old tutorial.

Please take a look at the Electron quick start guide.

EDIT: direct access to the Electron API from the renderer process has been deprecated in newer versions of Electron due to security concerns.

Electron has introduced Context Isolation instead. As mentioned in the documentaton, Context Isolation is a feature that ensures that both your preload scripts and Electron's internal logic run in a separate context to the website you load in a webContents. This is important for security purposes as it helps prevent the website from accessing Electron internals or the powerful APIs your preload script has access to.

You need to create a preload script to expose the ipcRenderer send method to your renderer process.

// preload.js
const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('electron', {
  sendIpcMessage: (channel, data) => {
    ipcRenderer.send(channel, data);
  }
});

You need to pass this script to the renderer process:

// main.js
const { app, BrowserWindow, ipcMain } = require('electron')
const path = require('node:path')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js')
    }
  })

  ipcMain.on('key', (event, key) => {
    alert(`received ${key}`)
  })

  win.loadFile('index.html')
}

app.whenReady().then(() => {
  createWindow()
})

You should now be able to access the method in your renderer:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="assets/bootstrap.min.css">
</head>
<body>
  <h1>gangway app</h1>
  <button  id="sendBtn">Send</button>
  <script>
    const { sendIpcMessage } = window.electron;

    let sendBtn = document.querySelector("#sendBtn");
    sendBtn.addEventListener('click', () => {
      alert("Alert");
      sendIpcMessage("key", "Gangway Test");
    });
  </script>
</body>
</html>

Please note that I haven't tested this, but this is the rough idea of what you need to do based on the documentation.

CodePudding user response:

the issue might be related to the context isolation in Electron.

Context Isolation is a security feature of Electron that allows scripts running in the renderer to make changes to its JavaScript environment without worrying about conflicting with the scripts in the Electron API or the preload script.

Starting from Electron 12, context isolation is enabled by default. This means that the ipcRenderer cannot be accessed directly from the renderer process because it's only available in the preload script.

You can create a preload script and expose specific IPC methods to your renderer process. Here's an example of how you can do it:

// In your preload script
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld(
  'electron',
  {
    send: (channel, data) => ipcRenderer.send(channel, data),
    receive: (channel, callback) => ipcRenderer.on(channel, (event, ...args) => callback(...args))
  }
)

Then in your HTML file, you can use these methods like this:

<script>
  let sendBtn = document.querySelector("#sendBtn");
  sendBtn.addEventListener('click',()=>{
    alert("Alert")
    window.electron.send("key","Gangway Test")
  })
</script>

And in your main process:

ipcMain.on('key', (event, arg) => {
  console.log(arg) // prints "Gangway Test"
})

Remember to set the path of your preload script in your BrowserWindow options:

new BrowserWindow({
  webPreferences: {
    preload: path.join(__dirname, 'preload.js')
  }
})

This way, you're not disabling any security features.

CodePudding user response:

Calling alert directly won't work in electron try to use window.alert() instead

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="assets/bootstrap.min.css">
</head>
<body>
  <h1>gangway app</h1>
  <button  id="sendBtn">Send</button>
  <script>
    const electron = require("electron")
    const {ipcRenderer} = electron

    let sendBtn = document.querySelector("#sendBtn");
    sendBtn.addEventListener('click',()=>{
      alert("Alert")
      ipcRenderer.send("key","Gangway Test")
    })
  </script>
</body>
</html>

However it's better to use something like notification if it's not just for testing.

  • Related