Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
187 views
in Technique[技术] by (71.8m points)

python - Cannot read property 'join' of undefined in Javascript file Electron JS

I have an application in Electron JS that is calling a python function to execute a python script. When the script executes it should send the data back to the Electron JS GUI and display it.

The issue I am having is that it is saying that join is undefined:

weather.js:9 Uncaught TypeError: Cannot read property 'join' of undefined at get_weather (weather.js:9) at HTMLButtonElement.onclick (weather.html:14)

here is my JavaScript file:

let {PythonShell} = require('python-shell')
var path = require("path")

function get_weather() {

  var city = document.getElementById("city").value

  var options = {
    scriptPath : path.join(__dirname, '/../engine/'),
    args : [city]
  }

  let pyshell = new PythonShell('weatherApp.py', options);


  pyshell.on('message', function(message) {
    swal(message);
  })
  document.getElementById("city").value = "";
}

The line "scriptPath : path.join(__dirname, '/../engine/')," seems to be the offending piece of code.

My gui.html file is as follows:

<html>
  <head>
    <title></title>
    <meta charset="UTF-8">
  </head>
  <body>

    <h1>Get your local weather ...</h1>
    <br>
    <br>
    <label>Enter city name here: <label>
    <input id="city" type = "text" placeholder="City">
    <button type = "button" value="clickme" onclick="get_weather()">Get Weather</button>
    <!--- <button class="btn btn-success" onclick="get_weather();">Go!</button> -->
    <br>
    <br>
    <br>
    <script src="/home/ironmantis7x/Documents/BSSLLC/projects/node_electron/electronDemoApps/guiApp/gui/linkers/weather.js"></script>
    <p><button type="button"><a href="gui.html">Back to Main Page</a></button>

  </body>
</html>

What error(s) do I need to fix to get this working correctly?

Thank you.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The Problem

Since Electron 5 nodeIntegration is disabled by default in the window. Since normal browser API does not know require or join, you get errors when you try.

Reenabling nodeIntegration

You could enable nodeIntegration again, but it was disabled for a reason. Be sure you read and understand the electron security tutorial.

Using a preload script

Another way is to use a preload script. Let's have a look at the BrowserWindow documentation.

When creating a new BrowserWindow you can add several options. For this case we need the webPreferences.preload option:

Specifies a script that will be loaded before other scripts run in the page. This script will always have access to node APIs no matter whether node integration is turned on or off. The value should be the absolute file path to the script. When node integration is turned off, the preload script can reintroduce Node global symbols back to the global scope.

Be aware that the preload script is run in the renderer process.

Example

Following is an example app, that opens a window with a button that uses the electron dialog to select files. This would not work with disabled nodeIntegration but thanks to our preload script, we reintroduced dialog.showOpenDialog() to our window.

main.js

const { app, BrowserWindow } = require("electron");
const { join } = require("path");

let win;

app.on("ready", () => {
  win = new BrowserWindow({
    webPreferences: {
      //this is the default since electron 5
      nodeIntegration: false,
      //here you load your preload script
      preload: join(__dirname, "preload.js")
    }
  });

  win.loadURL(join(__dirname, "index.html"));
});

preload.js

const { dialog } = require("electron").remote;

window.mystuff = {
  selectFile
};

async function selectFile() {
  const files = await dialog.showOpenDialog({
    properties: ["openFile", "multiSelections"]
  });

  return files;
}

index.html

<html>
  <body>
    <main>
      <button onclick="myFunction()">select file</button>
      <ul id="foo"></ul>
    </main>
    <script>
      async function myFunction() {
        //the function provided by the preload script
        const files = await window.mystuff.selectFile();

        const list = document.getElementById("foo");

        for (const file of files) {
          const node = document.createElement("LI");
          const textNode = document.createTextNode(file);
          node.appendChild(textNode);
          list.appendChild(node);
        }
      }
    </script>
  </body>
</html>

Sending events via IPC

If you are unsure your functionality should be exposed in the window, you can also send events via ipcRenderer.

preload.js

const { ipcRenderer } = require("electron");


window.mystuff = {
  selectFile
};


function selectFile() {
  return new Promise(resolve => {
    ipcRenderer.on("selected-files", (e, files) => {
      resolve(files);
    });

    ipcRenderer.send("select-files");
  });
}

Additional part in main.js


ipcMain.on("select-files", async () => {
  const files = await dialog.showOpenDialog({
    properties: ["openFile", "multiSelections"]
  });

  win.webContents.send("selected-files", files);
});


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...