This seems to be a not-uncommon question in JS circles, but I can’t seem to formulate a solution within PyScript. Below is a rudimentary setup for what will become a “rock paper scissors” game. The idea is to have the user click a button, “rock”, “paper”, or “scissors”, all three of which will fire a Python function that contains the game logic. For now, the function merely displays the user’s move and the computer’s move (determined at random). Each button passes an argument to the function–‘rock’, ‘paper’, or ‘scissors’-- and for now, the function should simply write back into the HTML the user and computer choices. The problem is, when written this way, all three buttons are firing the function on page load. While only the last call displays to the page, the console shows that all three are firing in order, each one overwriting the last. I need only one of the buttons to fire onClick. I haven’t had any problems triggering functions that take no arguments onclick and only onclick. It’s when I try to pass arguments that I get a problem. The fundamental question is how do I pass an argument to a pys-onClick (or py-onClick, depending on the version of PyScript) function without the function firing on page load? What am I missing?
Incidentally, an equivalent function written in JS performs as expected. See last code block below. The difference is, while the JS function recognizes “this.value” passed in from the buttons, Python does not.
<!-- HTML -->
...
<form onsubmit="return false">
<button class="button" id="rock" type="submit" pys-onClick="play('rock')">Rock</button>
<button class="button" id="paper" type="submit" pys-onClick="play('paper')">Paper</button>
<button class="button" id="scissors" type="submit" pys-onClick="play('scissors')">Scissors</button>
</form>
...
<!-- Placeholders for function output -->
<div id="user_move"></div>
<div id="computer_move"></div>
...
<py-script>
import random
MOVES = ["rock", "paper", "scissors"]
...
def play(move):
computer_move = random.choice(MOVES)
Element("user_move").write(move)
Element("computer_move").write(computer_move)
</py-script>
If it helps, here’s the entire script. Open the console and you’ll see that all three buttons are firing the function.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- Latest compiled and minified CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Latest compiled JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<!-- PyScript import -->
<script defer src="https://pyscript.net/alpha/pyscript.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-sm-2"></div>
<div class="col-sm-10">
<form onsubmit="return false">
<button class="submit" id="rock" type="submit" pys-onClick="play('rock')">Rock</button>
<button class="submit" id="paper" type="submit" pys-onClick="play('paper')">Paper</button>
<button class="submit" id="scissors" type="submit" pys-onClick="play('scissors')">Scissors</button>
</form>
</div>
</div>
<div class="row">
<div id="user_move"></div>
<div id="computer_move"></div>
</div>
</div>
<py-script>
import time
import random
MOVES = ["rock", "paper", "scissors"]
WIN_MSG = ["You win!", "You dropped the bomb on me! You win!", "Grrrr... You win. Jerk."]
LOSE_MSG = ["Ha ha! You lose!", "Don't bring that weak game in here! You lose!", "You might be good. But I'm better! Non-winner"]
TIE_MSG = ["Great minds think alike. We tied.", "I see the way you think. We tied.", "No joy! Tie."]
def play(move):
computer_move = random.choice(MOVES)
Element("user_move").write(move)
Element("computer_move").write(computer_move)
</py-script>
</body>
</html>
Same idea, written with JS:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- Latest compiled and minified CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Latest compiled JavaScript -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-sm-2"></div>
<div class="col-sm-10">
<form onsubmit="return false">
<button class="submit" id="rock" value="rock" type="submit" onClick="play(this.value)">Rock</button>
<button class="submit" id="paper" value="paper" type="submit" onClick="play(this.value)">Paper</button>
<button class="submit" id="scissors" value="scissors" type="submit" onClick="play(this.value)">Scissors</button>
</form>
</div>
</div>
<div class="row">
<div id="user_move"></div>
<div id="computer_move"></div>
</div>
</div>
<script>
function play(move) {
document.getElementById('user_move').innerHTML = move
}
</script>
</body>
</html>