Search code examples
javascripthtmlelectronipcrendereripcmain

electron app json data to renderer using ipc


i am new to electron so im sorry if my question is childish but i have sent some user inout data as object from renderer to main to store in json file (electron-db) but i want to show all data in a table i tired this by event.reply but it giving my desired result in preload's log only i dont know how to take it from preload to html table here i have attached my code from main

// catch obj This is Main.js
ipcMain.on("message", (event, obj) => {
  db.createTable("medicine", (succ, msg) => {
    // succ - boolean, tells if the call is successful
    if (succ) {
      console.log(msg);
    } else {
      console.log("An error has occured. " + msg);
    }
  });

  console.warn(obj);
  if ((db.valid("medicine"), location)) {
    db.insertTableContent("medicine", obj, (succ, msg) => {
      // succ - boolean, tells if the call is successful
      console.log("Success: " + succ);
      console.log("Message: " + msg);
    });
  }
  let row;
  const app = electron.app || electron.remote.app;

  db.getAll("medicine", (succ, data) => {
    // succ - boolean, tells if the call is successful
    // data - array of objects that represents the rows.
    // console.warn(data);
    row = data;
  });
  console.warn(row)
  event.reply("message", row)
});

and this is my preload

const {contextBridge, ipcMain, ipcRenderer} = require('electron');

const API = {
    sendmsg: (obj) => ipcRenderer.send("message", obj)
}
// const getAllData = function fetchData(){
//       ipcRenderer.send("req", "this is requirment for All data")
// }
ipcRenderer.on("message", (_event, row) => {
    console.log(row)
  })
contextBridge.exposeInMainWorld("api", API);

consol.log(row) giving my an array of all data in my db but i dont know how to make it availabe in html files script or in renderer


Solution

  • The wiring of your IPC is a bit mixed up and confusing. To simplify your scripts, try separating them into their own functionality. IE: Use your preload.js script to allow communication between the main process and render process(es) only.

    Not knowing what database you are using, I will assume your database code is correct and functional.

    Below is an example of how I would set-up my preload.js script and use it to communicate between processes.


    This preload.js script uses whitelisted channel names to identify which IPC lines of communication can be used, similar to Node.js eventName.

    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': [],
            // From main to render.
            'receive': [],
            // From render to main and back again.
            'sendReceive': [
                'message' // Channel name
            ]
        }
    };
    
    // 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);
                }
            }
        }
    );
    

    For brevity, I have included your database code within the below main.js file.

    main.js (main process)

    'use strict';
    
    const electronApp = require('electron').app;
    const electronBrowserWindow = require('electron').BrowserWindow;
    const electronIpcMain = require('electron').ipcMain;
    
    const nodePath = require("path");
    
    // db = require('db'); // Your (connected) database
    
    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')
            }
        });
    
        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();
        }
    });
    
    // ---
    
    // From render to main and back again
    electronIpcMain.handle('message', (event, obj) => {
        // Create the table
        db.createTable("medicine", (succ, msg) => {
            if (succ) {
                console.log(msg);
            } else {
                console.log('An error has occurred. ' + msg);
            }
        });
    
        console.warn(obj);
    
        // Insert your data object
        if ((db.valid("medicine"), location)) {
            db.insertTableContent("medicine", obj, (succ, msg) => {
                console.log('Success: ' + succ);
                console.log('Message: ' + msg);
            });
        }
    
        let rows;
    
        // Retrieve all rows
        db.getAll("medicine", (succ, data) => {
            // succ - boolean, tells if the call is successful
            // data - array of objects that represents the rows.
            // console.warn(data);
            rows = data;
        });
    
        console.warn(rows);
    
        return rows; // Simple return the result via IPC
    
        // Testing purposes.
        // let rows = [
        //     {"name": "Amoxicillin", "weight": "250mg"},
        //     {"name": "Codeine", "weight": "50mg"},
        //     {"name": "Penicillin", "weight": "25mg"}
        // ];
        //
        // rows.push(obj);
        //
        // console.log(rows);
        //
        // return rows;
    })
    

    Lastly, I have tried to implement what the basic functionality of your index.html file may be like.

    index.html (render process)

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Medicine</title>
        </head>
    
        <body>
            <h1>Add Medicine</h1>
        
            <label for="name">Name: </label>
            <input id="name" type="text">
    
            <label for="weight">Weight: </label>
            <input id="weight" type="text">
    
            <input id="button" type="button" value="Add">
        </body>
    
        <script>
            let name = document.getElementById('name');
            let weight = document.getElementById('weight');
    
            document.getElementById('button').addEventListener('click', () => {
                // From render to main and (.then) back again
                window.ipcRender.invoke('message', {"name": name.value, "weight": weight.value})
                    .then((rows) => {
                        console.log(rows);
                    })
            })
        </script>
    </html>