python-eel / Eel

A little Python library for making simple Electron-like HTML/JS GUI apps
MIT License
6.44k stars 587 forks source link

Using Eel calling JavaScript function in python only when a button is clicked #507

Closed ghost closed 3 years ago

ghost commented 3 years ago

Describe the problem I am trying to call a JavaScript function but only when a button is clicked , currently I am able to call JavaScript function but it trigger's as soon as the UI is opened how can I avoid it as am new to Eel

Expected When btn1 is clicked function name2 should fire in python code i.e just want to end value from js to python when btn1 in clicked

Code snippet(s) Here is some code that can be easily used to reproduce the problem or understand what I need help with.

import time

import eel

eel.init("web")

@eel.expose
def printFromPython():
    return "hello from python"

@eel.expose
def getTime():
    return time.strftime('%c')

#creating a  python function to use js returned vals
def print_num(n):
    result = n
    print('Got this from Javascript:', result)
    print(result['c'])
    print(result['un'])
    print(result.keys())

print('Calling Javascript...')
eel.name2()(print_num)

eel.start('main.html')

...
<html>
   <html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <meta name="Description" content="Enter your description here" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css" />
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" />
  <title>Simple Demo</title>
</head>

<body>
  <div>
    <h3 class="text-center alert-info">Just A Simple Demo</h3>
    <p class="text-center alert-danger" id="demo"></p>
    <div class="container-fluid text-center ">
      <input class="form-control btn btn-outline-success m-3" placeholder="Enter username" id="un">
      <input class="form-control btn btn-outline-success m-3" placeholder="Enter password" id="pwd">
      <button class="btn btn-primary m-3" id="btn1">Click Me Regular from JS</button>

    </div>
  </div>

  <script type="text/javascript" src="/eel.js"></script>
  <script src="main.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.slim.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.1/umd/popper.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.min.js"></script>

</body>

</html>
const d = new Date();
document.getElementById("demo").innerHTML = d;

function name1() {

  var username = document.getElementById("un").value
  var password = document.getElementById("pwd").value

  alert(username + ":" + password);
  document.getElementById("un").value = ""
  document.getElementById("pwd").value = ""
}

eel.expose(name2);

function name2() {;

  const c = "Hello lp from JS"

  var username = document.getElementById("un").value
  var password = document.getElementById("pwd").value
  console.log(c)
  return {
    c: c,
    un: username
    pw: password
  };

}

document.getElementById("btn1").addEventListener("click", name1)

Desktop (please complete the following information):

ofoxsmith commented 3 years ago

I've copied your code and python is throwing an exception because you are calling a JS function before eel.start() has been run. Also, I rewrote your JS to fix syntax issues and to make it simpler. Working code: main.py


import time
import eel

eel.init("web")

@eel.expose
def printFromPython():
    return "hello from python"

@eel.expose
def getTime():
    return time.strftime('%c')

#creating a  python function to use js returned vals
def print_num(n):
    result = n
    print('Got this from Javascript:', result)
    print(result['c'])
    print(result['un'])
    print(result.keys())

print('Calling Javascript...')
eel.start('main.html', )

eel.name2()(print_num)

main.js

const d = new Date();
document.getElementById("demo").innerHTML = d;

function name1() {
  let username = document.getElementById("un").value;
  let password = document.getElementById("pwd").value;

  alert(username + ":" + password);
  document.getElementById("un").value = "";
  document.getElementById("pwd").value = "";
}

eel.expose(name2);
function name2() {
  let values = {
    c: "Hello lp from JS",
    username: document.getElementById("un").value,
    password: document.getElementById("pwd").value,

  };
  console.log(values.c);
  return values;
}

document.getElementById("btn1").addEventListener("click", name1)
ghost commented 3 years ago

I've copied your code and python is throwing an exception because you are calling a JS function before eel.start() has been run. Also, I rewrote your JS to fix syntax issues and to make it simpler. Working code: main.py


import time
import eel

eel.init("web")

@eel.expose
def printFromPython():
    return "hello from python"

@eel.expose
def getTime():
    return time.strftime('%c')

#creating a  python function to use js returned vals
def print_num(n):
    result = n
    print('Got this from Javascript:', result)
    print(result['c'])
    print(result['un'])
    print(result.keys())

print('Calling Javascript...')
eel.start('main.html', )

eel.name2()(print_num)

main.js

const d = new Date();
document.getElementById("demo").innerHTML = d;

function name1() {
  let username = document.getElementById("un").value;
  let password = document.getElementById("pwd").value;

  alert(username + ":" + password);
  document.getElementById("un").value = "";
  document.getElementById("pwd").value = "";
}

eel.expose(name2);
function name2() {
  let values = {
    c: "Hello lp from JS",
    username: document.getElementById("un").value,
    password: document.getElementById("pwd").value,

  };
  console.log(values.c);
  return values;
}

document.getElementById("btn1").addEventListener("click", name1)

Thanks Smith pardon me for my incorrect question explanation I will try to rephrase my query suppose there is a button 4 on html now when I click on it I need values from input boxes to be passed to python so that there I can use these values is it possible here ?

`// need to send values from function name2 to python when btn4 is clicked ?

eel.expose(name2);
function name2() {
  let values = {
    c: "Hello lp from JS",
    username: document.getElementById("un").value,
    password: document.getElementById("pwd").value,

  };
  console.log(values.c,values.username,values.password);
  return values;
}

document.getElementById("btn4").addEventListener("click", name2)

`

ofoxsmith commented 3 years ago

Just get the values from HTML and pass them to a python function eg

  let input1 = document.getElementById("un").value,
  let input2 = document.getElementById("pwd").value,
  eel.python_func(input1, input2);
ghost commented 3 years ago

Just get the values from HTML and pass them to a python function eg

  let input1 = document.getElementById("un").value,
  let input2 = document.getElementById("pwd").value,
  eel.python_func(input1, input2);

thanks smith kindly pardon me still i am unable to figure it out as you told now i am clicking btn4 but how to see value from python side ..like expecting to print input1 when btn4 is clicked

import time
import eel

eel.init("web")

@eel.expose
def printFromPython():
    return "hello from python"

@eel.expose
def getTime():
    return time.strftime('%c')

# creating a  python function to use js returned vals
def print_fromjs(n):
    result = n
    print('Got this from Javascript:', result)
    # print(result['c'])
    # print(result['un'])
    # print(result.keys())

print('Calling Javascript...')
eel.start('main.html', )

eel.name2()(print_fromjs)
const d = new Date();
document.getElementById("demo").innerHTML = d;

// just a regular js func
function name1() {
  let username = document.getElementById("un").value;
  let password = document.getElementById("pwd").value;

  alert(username + ":" + password);
  document.getElementById("un").value = "";
  document.getElementById("pwd").value = "";
}

// just calling regular js func
document.getElementById("btn1").addEventListener("click", name1)

// calling python function
document.getElementById("btn2").addEventListener("click", function () {

  // here x in returned val from python
  eel.printFromPython()(x => {
    alert(x)
  })

})

// calling python function 2 WITH SYNC AWAIT 
document.getElementById("btn3").addEventListener("click", async function getTime() {
  let value = await eel.getTime()();
  alert(value);
})

// need to send values from function name2 to python when btn4 is clicked ?

eel.expose(name2);
function name2() {
    var input1 = document.getElementById("un").value,
    var input2 = document.getElementById("pwd").value,
    console.log(input1)
    eel.python_func(input1, input2);
}

document.getElementById("btn4").addEventListener("click", name2)
dstricks commented 3 years ago

Try this:

main.py

import time
import eel

eel.init("web")

@eel.expose
def printFromPython():
    return "hello from python"

@eel.expose
def getTime():
    return time.strftime('%c')

# creating a  python function to use js returned vals
@eel.expose
def print_fromjs(n):
    result = n
    print('Got this from Javascript:', result)
    print(result['un'])
    print(result['pwd'])
    print(result.keys())

print('Calling Javascript...')
eel.start('main.html', )

# eel.name2()(print_fromjs)  <This is not necessary>

main.js

const d = new Date();
document.getElementById("demo").innerHTML = d;

// just a regular js func
function name1() {
  let username = document.getElementById("un").value;
  let password = document.getElementById("pwd").value;

  alert(username + ":" + password);
  document.getElementById("un").value = "";
  document.getElementById("pwd").value = "";
}

// just calling regular js func
document.getElementById("btn1").addEventListener("click", name1)

// calling python function
document.getElementById("btn2").addEventListener("click", function () {

  // here x in returned val from python
  eel.printFromPython()(x => {
    alert(x)
  })

})

// calling python function 2 WITH SYNC AWAIT 
document.getElementById("btn3").addEventListener("click", async function getTime() {
  let value = await eel.getTime()();
  alert(value);
})

// need to send values from function name2 to python when btn4 is clicked ?

eel.expose(name2);
function name2() {
    var un = document.getElementById("un").value;
    var pwd = document.getElementById("pwd").value;
    console.log(un);
    eel.print_fromjs({un, pwd});
}

document.getElementById("btn4").addEventListener("click", name2)

The key is that your Python code must expose functions that you'd like to call from JavaScript, just like you did with the getTime(). In your original code, JavaScript was trying to call function python_func but the Python code did not expose any function called python_func. Since you already had Python function print_fromjs, I just exposed that in Python and called it from JavaScript.

ghost commented 3 years ago

Try this:

main.py

import time
import eel

eel.init("web")

@eel.expose
def printFromPython():
    return "hello from python"

@eel.expose
def getTime():
    return time.strftime('%c')

# creating a  python function to use js returned vals
@eel.expose
def print_fromjs(n):
    result = n
    print('Got this from Javascript:', result)
    print(result['un'])
    print(result['pwd'])
    print(result.keys())

print('Calling Javascript...')
eel.start('main.html', )

# eel.name2()(print_fromjs)  <This is not necessary>

main.js

const d = new Date();
document.getElementById("demo").innerHTML = d;

// just a regular js func
function name1() {
  let username = document.getElementById("un").value;
  let password = document.getElementById("pwd").value;

  alert(username + ":" + password);
  document.getElementById("un").value = "";
  document.getElementById("pwd").value = "";
}

// just calling regular js func
document.getElementById("btn1").addEventListener("click", name1)

// calling python function
document.getElementById("btn2").addEventListener("click", function () {

  // here x in returned val from python
  eel.printFromPython()(x => {
    alert(x)
  })

})

// calling python function 2 WITH SYNC AWAIT 
document.getElementById("btn3").addEventListener("click", async function getTime() {
  let value = await eel.getTime()();
  alert(value);
})

// need to send values from function name2 to python when btn4 is clicked ?

eel.expose(name2);
function name2() {
    var un = document.getElementById("un").value;
    var pwd = document.getElementById("pwd").value;
    console.log(un);
    eel.print_fromjs({un, pwd});
}

document.getElementById("btn4").addEventListener("click", name2)

The key is that your Python code must expose functions that you'd like to call from JavaScript, just like you did with the getTime(). In your original code, JavaScript was trying to call function python_func but the Python code did not expose any function called python_func. Since you already had Python function print_fromjs, I just exposed that in Python and called it from JavaScript.

Thanks #dstricks for clarifications just what i was looking for

ghost commented 3 years ago

Try this:

main.py

import time
import eel

eel.init("web")

@eel.expose
def printFromPython():
    return "hello from python"

@eel.expose
def getTime():
    return time.strftime('%c')

# creating a  python function to use js returned vals
@eel.expose
def print_fromjs(n):
    result = n
    print('Got this from Javascript:', result)
    print(result['un'])
    print(result['pwd'])
    print(result.keys())

print('Calling Javascript...')
eel.start('main.html', )

# eel.name2()(print_fromjs)  <This is not necessary>

main.js

const d = new Date();
document.getElementById("demo").innerHTML = d;

// just a regular js func
function name1() {
  let username = document.getElementById("un").value;
  let password = document.getElementById("pwd").value;

  alert(username + ":" + password);
  document.getElementById("un").value = "";
  document.getElementById("pwd").value = "";
}

// just calling regular js func
document.getElementById("btn1").addEventListener("click", name1)

// calling python function
document.getElementById("btn2").addEventListener("click", function () {

  // here x in returned val from python
  eel.printFromPython()(x => {
    alert(x)
  })

})

// calling python function 2 WITH SYNC AWAIT 
document.getElementById("btn3").addEventListener("click", async function getTime() {
  let value = await eel.getTime()();
  alert(value);
})

// need to send values from function name2 to python when btn4 is clicked ?

eel.expose(name2);
function name2() {
    var un = document.getElementById("un").value;
    var pwd = document.getElementById("pwd").value;
    console.log(un);
    eel.print_fromjs({un, pwd});
}

document.getElementById("btn4").addEventListener("click", name2)

The key is that your Python code must expose functions that you'd like to call from JavaScript, just like you did with the getTime(). In your original code, JavaScript was trying to call function python_func but the Python code did not expose any function called python_func. Since you already had Python function print_fromjs, I just exposed that in Python and called it from JavaScript.

Thanks #dstricks for clarifications just what i was looking for

ghost commented 3 years ago

Try this:

main.py

import time
import eel

eel.init("web")

@eel.expose
def printFromPython():
    return "hello from python"

@eel.expose
def getTime():
    return time.strftime('%c')

# creating a  python function to use js returned vals
@eel.expose
def print_fromjs(n):
    result = n
    print('Got this from Javascript:', result)
    print(result['un'])
    print(result['pwd'])
    print(result.keys())

print('Calling Javascript...')
eel.start('main.html', )

# eel.name2()(print_fromjs)  <This is not necessary>

main.js

const d = new Date();
document.getElementById("demo").innerHTML = d;

// just a regular js func
function name1() {
  let username = document.getElementById("un").value;
  let password = document.getElementById("pwd").value;

  alert(username + ":" + password);
  document.getElementById("un").value = "";
  document.getElementById("pwd").value = "";
}

// just calling regular js func
document.getElementById("btn1").addEventListener("click", name1)

// calling python function
document.getElementById("btn2").addEventListener("click", function () {

  // here x in returned val from python
  eel.printFromPython()(x => {
    alert(x)
  })

})

// calling python function 2 WITH SYNC AWAIT 
document.getElementById("btn3").addEventListener("click", async function getTime() {
  let value = await eel.getTime()();
  alert(value);
})

// need to send values from function name2 to python when btn4 is clicked ?

eel.expose(name2);
function name2() {
    var un = document.getElementById("un").value;
    var pwd = document.getElementById("pwd").value;
    console.log(un);
    eel.print_fromjs({un, pwd});
}

document.getElementById("btn4").addEventListener("click", name2)

The key is that your Python code must expose functions that you'd like to call from JavaScript, just like you did with the getTime(). In your original code, JavaScript was trying to call function python_func but the Python code did not expose any function called python_func. Since you already had Python function print_fromjs, I just exposed that in Python and called it from JavaScript.

Thanks #dstricks for clarifications just what i was looking for

gracyashhh commented 2 years ago

hey @dstricks Can you please help me with this, I have a very similar query and am unable to find the answers elsewhere

Describe the problem I am trying to call a JavaScript function but only when a if condition evaluates to True in Python. I'm working on a Music player project with Pygame and Eel, I want to call the JS function to change Song cover image automatically without a button click as the previous song ends, which am finding using pygame.mixer.music.get_busy() in python, during when I want to call the 'eel.fine()' but I'm sure why it's not working or how to get this done as am new to Eel

Expected When if condition becomes True function find should be called from python code i.e just want to change cover image when one song ends Code snippet(s) Here is some code that can be easily used to reproduce the problem or understand what I need help with. Note: I have removed most part of the code just to make to understand and have only added the portions that relate to the flow of the code what I need help with.

import eel
from pygame import mixer

eel.init('web')

js='function $fine(){document.getElementById("spl").live("click");}'
def my_update():
    if pausev and not fine:
        if not start and not mixer.music.get_busy():
            #ok=js2py.eval_js(js)
            # ok()
            print("booom")
            eel.fine()  # This is the part I need help with
            play()
            print('new song up')
        else:
            print('old playing still')
    else:
        print('strictly paused')
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="description" content="">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Aishu's Magic-Music</title>
    <link href="style.css" rel="stylesheet">
    <script type="text/javascript" src="/eel.js"></script>
    <script type="text/javascript" src="main.js"></script>
    <script type="text/javascript">
        eel.expose(fine);
      function fine(){
      document.getElementById("spl").live("click");

      }
    </script>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js" type="text/javascript"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
</head>

<body>
    <section class="wellcome_area clearfix" id="home">
      <div class="container h-100">
            <div class="row h-100 align-items-center">
                <div class="col-12 col-md">
                    <div class="get-start-area">
                        <form class="form-inline">
                            <input type="button" id="repeat" class="submit" value="▶ Shower" onclick="generateQRCode(7)">
                            <input type="button" id="spl" class="submit" value="▶ Play" onclick="generateQRCode(2)">
                            <input type="button" class="submit" value=">> Skip" onclick="generateQRCode(3)">
                        </form>
                    </div>
                </div>
            </div>
        </div>
        <div class="welcome-thumb ">
            <img id="qr" class="headshot headshot-1" src="img/bg-img/play.jpg" width="50%">
        </div>
    </section>

</body>
</html>
// main.js
var whatever=1;
var loop_check=1;
function generateQRCode(data) {
    if(data==2){
    change()
     if(whatever==1){
        eel.generate_qr(1)(setImage);
        whatever=0;
    }
    else
    {
        eel.generate_qr(data)(setImage)

    }
    }
    else if(data==7){
    change_loop()
    eel.generate_qr(data)(setImage)
    }
    else{
    eel.generate_qr(data)(setImage)
    }
}
function change() 
{
    var elem = document.getElementById("spl");
    if (elem.value=="|| Pause") elem.value = "▶ Play";
    else elem.value = "|| Pause";

}
function setImage(base64) {
    document.getElementById("qr").src = base64
}

Desktop (please complete the following information):

dstricks commented 2 years ago

Looks like you cross-posted on StackOverflow and figured it out.

gracyashhh commented 2 years ago

Lol @dstricks I was so desperate to figure that out, btw to my surprise, I solved that myself and hence added the same there too :) Btw Thanks I didn't actually expect such a soon reply!