Trying to send data from one electron window to another via ipc - javascript

Building my first electron app and I'd like the workflow to be as follows:
mainWindow opens -> user clicks 'open' button -> 2nd window opens -> user enters input/hits submit -> mainWindow opens back up displaying user input
Below is my app.on('ready') from my main.js. The application startup (win.loadURL) works fine, as does the open-new-window event. The weirdness comes in the input-broadcast.
When the user enters input in the second window, the main window will re-open. However, the text in the console.log in the input-broadcast does not appear, and the input-received never fires in the main window's renderer.
Not sure what I'm doing wrong, however I may be using the wrong design pattern as well. Any help would be greatly appreciated!
main.js
const {app, BrowserWindow, ipcMain, remote} = require('electron');
const url = require('url');
const path = require('path');
const countdown = require('./countdown');
let win;
const windows = [];
app.on('ready', () =>{
console.log('app ready');
ipcMain.on('open-new-window', () =>{
console.log('trying to open window');
win.loadURL(url.format({
pathname: path.join(__dirname, 'enterValue.html'),
protocol: 'file:',
slashes: true
}));
});
ipcMain.on('input-broadcast', (evt, data) =>{
console.log('input-broadcast happened in main');
win.webContents.send('input-received', data);
win.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}));
});
win = new BrowserWindow({width: 800, height: 600});
win.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}));
win.on('closed', () =>{
console.log('closed');
win = null;
});
})
renderer.js (assoc. with the index.html)
console.log('from renderer1');
const {ipcRenderer} = require('electron');
document.getElementById('start').addEventListener('click', ()=>{
ipcRenderer.send('open-new-window');
console.log('window button clicked');
});
ipcRenderer.on('open-new-window', (evt, count) =>{
document.getElementById('userInput').innerHTML(count);
});
ipcRenderer.on('input-received', (evt, data) =>{
console.log('input received');
console.log(evt);
console.log(data);
});
renderer2.js (assoc. with the user enterValue.html)
console.log('from renderer2');
const {ipcRenderer} = require('electron');
document.getElementById('submitButton').addEventListener('click', (evt, input)=>{
var input = document.getElementById('randomInput').value;
ipcRenderer.send('input-broadcast', input);
});
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<p>Your input was <span id="userInput"></span><p>
<button id="start">Open</button>
<script>require('./renderer')</script>
</html>
enterValue.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>Enter a name</p>
<input type="text" id="randomInput" placeholder="enter a value"/>
<button id="submitButton">Submit</button>
<script>require('./renderer2.js')</script>
</body>
</html>

Your call order is not right when sending input back to renderer.js. You call
win.webContents.send('input-received', data)
when index.html is not yet re-loaded into win!
To fix this you should swap the calls and make sure that the content is ready when you send ipc message
ipcMain.on('input-broadcast', (evt, data) => {
console.log('input-broadcast happened in main')
win.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
win.webContents.once('dom-ready', () => {
win.webContents.send('input-received', data)
})
})

Related

electron Cannot read properties of undefined

It is my first time using electron and I faced this error while creating a quit button.
I went thru like 50 threads and most of them said use require('#electron/remote/main').initialize()
and it did not work
electron version :20.1.1
should I downgrade electron to work?
or should I reinstall electron?
or maybe create a new project?
Uncaught TypeError: Cannot read properties of undefined (reading 'getCurrentWindow')
at document.getElementById.onclick (render.js:6:25)
my index.js file:
const { app, BrowserWindow } = require('electron');
const path = require('path');
require('#electron/remote/main').initialize();
if (require('electron-squirrel-startup')) {
app.quit();
}
const createWindow = () => {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
frame: false,
enableRemoteModule: true,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
webPreferences: true,
preload: path.join(__dirname, 'preload.js'),
},
});
// and load the index.html of the app.
mainWindow.loadFile(path.join(__dirname, 'index.html'));
// Open the DevTools.
mainWindow.webContents.openDevTools();
};
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
render.js
const { remote } = require('#electron/remote')
document.getElementById('close').onclick = function() {
console.log("debug")
var window = remote.getCurrentWindow();
window.close();
}
and html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Instapath</title>
<link rel="stylesheet" href="index.css" />
<script defer src="render.js"></script>
</head>
<body class="content">
<button id="close" style="position:fixed;">Close</button>
<div><h1>Hi!</h1></div>
</body>
</html>

Uncaught ReferenceError: Cannot access 'socket' before initialization only on electron

I am trying to set up an electron app where i send a message to the server, and the server puts the value on the readonly textarea.
But, when i start the app, i see this in the devtoools console:
Uncaught ReferenceError: Cannot access 'socket' before initialization
But, when i open my browser (outside the electron app), it works as i wanted
why my code works as planned on my browser, but not on my electron?
//SERVER HOSTING SECTION
const express = require('express')
const http = require('http')
const socketIo = require('socket.io')
const serverapp = express()
const server = http.createServer(serverapp)
let mensagem
serverapp.use(express.static(__dirname+'/data'))
const io = socketIo.listen(server);
server.listen(8889, ()=>console.log("adm online na porta http://localhost:7000"))
serverapp.get("/",function(req,res){
res.sendFile(path.resolve("index.html"));
})
io.on('connection', (socket) => {
console.log("nova conexao")
socket.on('mensagem',(mensagem)=>{
console.log("mensagem aqui:", mensagem)
io.emit('resposta',mensagem)
})
});
//ELECTRON APP SECTION
const {app, BrowserWindow} = require('electron')
const path = require('path')
function createWindow () {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, 'preload.js')
}
})
mainWindow.loadFile('data/index.html')
//mainWindow.loadURL("http://localhost:7000/index.html");
// Open the DevTools.
mainWindow.webContents.openDevTools()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
/*
$.getScript("server.js",function(){
console.log("a")
})
*/
// index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="estilo.css">
<script src="socket.io/socket.io.js"></script>
<title>Hello World!</title>
</head>
<body>
<h1>aaaaaaaaaa</h1>
<div>
<input type="text" id="textbox" value="aba">
<button onclick ="adicionar()"type="button" id="botao" for="textbox">Enviar</button>
<button onclick ="enviar()"type="button" id="botao2" >Teste</button>
</div>
<textarea name="" id="textarea" cols="30" rows="10" readonly></textarea>
<script src="codigo.js"></script>
</body>
</html>
<!-- begin snippet: js hide: false console: true babel: false -->
// code that sends and receives the message
let botaoAdicionar=document.querySelector("#botao")
let textbox = document.querySelector('#textbox')
let textarea = document.querySelector("#textarea")
let valortextbox;
console.log(valortextbox)
const socket = io.connect()
function adicionar(){
event.preventDefault();
console.log(textbox.value)
textarea.value+=textbox.value
};
socket.on('resposta',(mensagem)=>{
textarea.textContent+=mensagem
console.log('resposta recebida')
})
function enviar(){
let valortextbox= textbox.value
socket.emit('mensagem', valortextbox)
console.log("a")
}
/*
let testbtn=document.querySelector("#botao2")
testbtn.addEventListener("click", function(){
console.log("a")
})
*/
Problem solved, i just needed to add "nodeIntegration: true" on browser window
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
preload: path.join(__dirname, 'preload.js')
}
})

How to grant permission to audio in electron app in Windows?

I'm trying to implement speech recognition into the electron application. The solution works in chrome browser, but does not work in electron. The application stops listening immediately - it probably has no microphone permission. How to grant permissions?
index.js
const electron = require('electron');
const url = require('url');
const path = require('path');
const { app, BrowserWindow, ipcMain } = electron;
let mainWindow;
ipcMain.on('close-me', (evt, arg) => {
app.quit()
})
app.on('ready', () => {
mainWindow = new BrowserWindow({
transparent: true,
frame: false,
webPreferences: {
nodeIntegration: true,
webviewTag: true
}
});
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'web/index.html'),
protocol: 'file',
slashes: true
}));
mainWindow.webContents.openDevTools();
mainWindow.setFullScreen(true);
});
index.html
<!doctype html>
<html lang="en">
<head>
<title></title>
<link rel="stylesheet" href="styles/style.css">
</head>
<body>
<div class="container">
<button id="rec"> rec</button>
<button id="endrec"> end</button>
</div>
<script src="scripts/speech.js"></script>
</body>
</html>
speech.js
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const recognition = new SpeechRecognition();
recognition.lang = 'pl-PL';
const rec = document.querySelector('#rec');
const endrec = document.querySelector('#endrec');
recognition.onstart = function () {
console.log('I started');
}
recognition.onend = function () {
console.log('I finished');
}
recognition.onresult = function () {
console.log('Take what I recorded');
console.log(event);
const current = event.resultIndex;
const transcript = event.results[current][0].transcript;
console.log(transcript);
}
rec.addEventListener('click', () => {
recognition.start();
console.log('You clicked me');
})
endrec.addEventListener('click', () => {
recognition.stop();
})
I've also tried solutions with
webview.addEventListener('permissionrequest', function (e) {
if (e.permission === 'media') {
e.request.allow();
}
});
and
navigator.webkitGetUserMedia({ audio: true })
UPDATE
I found a reason to stop recognizing - error - network
I think you'll want to use the setPermissionRequestHandler on your session, like this:
const electron = require('electron');
const url = require('url');
const path = require('path');
const {
app,
BrowserWindow,
ipcMain,
session
} = electron;
let mainWindow;
ipcMain.on('close-me', (evt, arg) => {
app.quit()
})
app.on('ready', () => {
mainWindow = new BrowserWindow({
transparent: true,
frame: false,
webPreferences: {
nodeIntegration: true,
webviewTag: true
}
});
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'web/index.html'),
protocol: 'file',
slashes: true
}));
mainWindow.webContents.openDevTools();
mainWindow.setFullScreen(true);
session.fromPartition("default").setPermissionRequestHandler((webContents, permission, callback) => {
let allowedPermissions = ["audioCapture"]; // Full list here: https://developer.chrome.com/extensions/declare_permissions#manifest
if (allowedPermissions.includes(permission)) {
callback(true); // Approve permission request
} else {
console.error(
`The application tried to request permission for '${permission}'. This permission was not whitelisted and has been blocked.`
);
callback(false); // Deny
}
});
});
I've faced similar problem myself and found out that google doesn't provide speechAPI for CLI based apps like electron. Your best bet is to use either Google Cloud Speech API or any third-party API like Microsoft Cognitive Service.
Are you testing on MacOS? I faced a similar issue in my MBP, and below check solved the issue -
systemPreferences.askForMediaAccess(microphone)
See the Electron doc reference for additional details.

Electron app runs without any errors however the window does not open or show in task manager

I am building an electron app. The app runs without any errors but does not open. I am running windows 7 on a 32 bit machine. My main.js file looks like this:
const {app, BrowserWindow} = require('electron');
const path = require('path');
const url = require('url');
// Initialize window
let win;
function createWindow() {
win = new BrowserWindow({
width: 800,
height: 600,
icon: __dirnaname+ '/assets/images/icon.jpg'
});
// Load Window
win.loadUrl(url.format({
pathname: path.join(__dirname, './index.html'),
protocol: 'file',
slashes: true
}));
// Close window
win.on('closed', () =>{
win = null;
});
//Run Create Window Function
win.on('ready', createWindow);
//Check Mac OS platform
app.on('all-window-closed', () => {
if(process.platform !== 'darwin') {
app.quit();
}
});
};
This line is wrong
win.on('ready', createWindow);
you meant
app.on('ready', createWindow);
outside of createWindow's scope. Like this:
function createWindow() {
...
};
app.on('all-window-closed', () => {
...
});
app.on('ready', createWindow);
I had the same problem after I upgraded electron from v3.x to v8.x it started working

electron loadURL re-renders the same page

I'm trying to receive the name of a new file from the front-end using ipcRenderer, sending it to electron and using ipcMain to listen to this event and load a new view for the window. However, the loadURL re-renders the same view. I've checked and made sure that the correct name is sent back back and that the path to the file is correct.
Here is a code snippet of the two method calls:
let win
const createWindow = () => {
win = new BrowserWindow({width: 800, height: 600})
win.loadURL(url.format({
pathname: path.join(__dirname, '/src/index.ejs'),
protocol: 'file:',
slashes: true
}));
};
app.on('ready', createWindow);
ipcMain.on('redirectToView', (event, metadata) => {
const pathToView = `${__dirname}/src/views/${metadata.viewName}.ejs`;
const URL = url.format({
pathname: pathToView,
protocol: 'file:',
slashes: true
})
win.loadURL(URL);
})

Categories

Resources