Uncaught (in promise) JavaScript - Skulpt Input Function - javascript

Im trying to write a Python code editor in browser using Skulpt to execute the Python code and Code Mirror as a text editor.
As the input function for Skulpt uses an alert for input, I have decided to write my own function. The input function I have written works and takes an input from a modal.
Sk.configure({output:outf, read:builtinRead, __future__: Sk.python3, inputfun: function (prompt) {
clearModal();
addModalQuestion(prompt);
toggleModal();
// the function returns a promise to give a result back later...
return new Promise(function(resolve,reject){
$("#modal-submit").on("click",function(e){
// resolve the promise with the value of the input field
resolve($("#modal-input").val());
})
})
}, inputfunTakesPrompt: true});
Any errors in the code are usually sent to the output pre:
For normal errors with no input I get this (which is what I want to happen):
However, when I use an input in my code no error message is output:
The errors will no longer be displayed and I receive the following error:
Does anyone have any idea how I could resolve this issue or point me in the right direction?
I've put both my skulpt.js and index.html file below if this helps.
SkulptTest.js
// output functions are configurable. This one just appends some text
// to a pre element.
function outf(text) {
var mypre = document.getElementById("output");
mypre.innerHTML = mypre.innerHTML + text;
}
function builtinRead(x) {
if (Sk.builtinFiles === undefined || Sk.builtinFiles["files"][x] === undefined)
throw "File not found: '" + x + "'";
return Sk.builtinFiles["files"][x];
}
// Here's everything you need to run a python program in skulpt
// grab the code from your textarea
// get a reference to your pre element for output
// configure the output function
// call Sk.importMainWithBody()
function runit() {
var prog = editor.getValue(); ;
var mypre = document.getElementById("output");
mypre.innerHTML = '';
Sk.pre = "output";
Sk.configure({output:outf, read:builtinRead, __future__: Sk.python3, inputfun: function (prompt) {
clearModal();
addModalQuestion(prompt);
toggleModal();
// the function returns a promise to give a result back later...
return new Promise(function(resolve,reject){
$("#modal-submit").on("click",function(e){
// resolve the promise with the value of the input field
resolve($("#modal-input").val());
})
})
}, inputfunTakesPrompt: true});
(Sk.TurtleGraphics || (Sk.TurtleGraphics = {})).target = 'mycanvas';
var myPromise = Sk.misceval.asyncToPromise(function() {
try {
if (result = Sk.importMainWithBody("<stdin>", false, prog, true)) {
return result;
}
}
catch(e) {
outf(e.toString());
}
});
;
}
index.html
<!DOCTYPE html>
<html>
<head>
<!--JQuery-->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js" type="text/javascript"></script>
<!--Skulpt-->
<script src="skulpt/skulpt.min.js" type="text/javascript"></script>
<script src="skulpt/skulpt-stdlib.js" type="text/javascript"></script>
<!--Code Mirror-->
<script src="codemirror/lib/codemirror.js"></script>
<link href="codemirror/lib/codemirror.css" rel="stylesheet">
<script src="codemirror/mode/python/python.js"></script>
<link href="codemirror/theme/midnight.css" rel="stylesheet">
<!--My Styles-->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Data Input</title>
<meta name="description" content="How do we input data in Python 3?">
<link href="css/reset.css" rel="stylesheet" type="text/css">
<style>
#editor-container {
width: 100vw;
height: 47vh;
}
#run-container {
width: 100vw;
height: 5vh;
background-color: #0a121f;
}
#run-container button {
float: right;
height: 5vh;
width: 15%;
background-color: yellow;
border: none;
border-radius: 5px;
}
#output-container {
width: calc(100vw - 10px);
height: calc(45vh - 10px);
background-color: aliceblue;
float: right;
background-color: #000;
color: #fff;
padding-left: 10px;
padding-top: 10px;
}
#output {
white-space: pre-wrap; /* css-3 */
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
</style>
<!--Modal-->
<link href="css/modal.css" rel="stylesheet" type="text/css">
</head>
<body>
<!--Skulp-->
<script src="skulptTest.js"></script>
<!--My Code-->
<div id="right-panel">
<div id="editor-container">
<div class="modal" id="modal">
<div class="modal-content">
<span class="close-button"></span>
<p id="modal-question" class="modal-question">Input Prompt</p>
<input type="text" id="modal-input" name="modal-input" class="modal-input">
<button id="modal-submit" class="modal-submit" onclick="toggleModal()">Submit</button>
</div>
</div>
<textarea id="editor"></textarea>
</div>
<div id="run-container">
<button type="button" onclick="runit()">Run</button>
</div>
</div>
<div id="output-container">
<pre id="output"></pre>
</div>
<!-- Code Mirror-->
<script src="js/code-mirror.js"></script>
<script>editor.setValue("name = input('What is your name?')\nprint(name)");</script>
</body>
</html>
<script src="js/modal.js"></script>
I've also attached a link to all of the files below.
Code Editor Files
If anyone could help me with this I'd really appreciate it
Thanks in advance,
Sean

Related

Fetch Request Causing Page reload

My page keeps on reloading after my fetch request is complete. I don't want the page to reload after I submit the form. Can anyone help out as to why even after using e.preventDefault() I get that behavior? Also can you suggest better formatting tips for JS as I'm a beginner and would like your input. I'm fetching the data from a fake REST API made using json-live-server
HTML
<!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">
<link rel="stylesheet" href="styles.css">
<title>Document</title>
</head>
<body class="body">
<h1> Vaccination Centers</h1>
<div id='app'>
<form id='form'>
<input type="text" id='enrollment' />
<input type='text' id='session' />
<button type="submit">submit</button>
</form>
</div>
<script type="module" src="main.js"></script>
</body>
</html>
JS
let listArray
function getCenters () {
fetch ('http://localhost:3001/students')
.then(
response => response.json()
)
.then(data => {
listArray = data
console.log(listArray)
})
};
function init () {
getCenters()
const form = document.getElementById('form')
form.addEventListener('submit', (e) => validate(e))
}
function validate (e) {
console.log(e)
e.preventDefault()
let enrollment = document.getElementById('enrollment').value
let student = listArray.find(s => s.enrollment.toString() === enrollment.toString())
fetch ('http://localhost:3001/students/' + student.id, {
method: 'PATCH',
headers: {
'Content-type': 'application/json; charset=UTF-8' // Indicates the content
},
body: JSON.stringify({ paidFee: true })
}).then(document.getElementById('app').innerHTML = 'HELLO BITCHES')
}
window.onload = init
We can all agree that e.preventDefault() placed at the first line  ⃰ in the event handler (aka validate(e)) will stop the default browser behavior of a <form> when a "submit" event is triggered on it. The behavior OP is observing is the destructive overwriting of the following:
.then(document.getElementById('app').innerHTML = 'HELLO BITCHES')
Just remove the above and you shouldn't have what appears as a page reload, but if you must say, "HELLO" to the bitches, use .insertAdjacentHTML() instead:
.then(document.getElementBYId('app').insertAdjacentHTML('beforeBegin', 'HELLO BITCHES'))
The following example has an event handler for the "submit" (submitter(e)) and "click" (clicker(e)) events. If button#A is clicked, .innerHTML is used and if button#B is clicked, .insertAdjacentHTML() is used. There is also a logger function (eventLogger(e)) which will log:
type of event........................................e.type
event listener #id............................e.currentTarget
button #id..........................................e.target.id (from 'click' event)
if default was prevented or not.....e.defaultPrevented
⃰actually it's console.log() at that position but there's no difference in this context
Best viewed in Full Page mode
document.forms[0].addEventListener('submit', submitter);
document.querySelectorAll('button').forEach(node => node.addEventListener('click', clicker));
function submitter(e) {
e.preventDefault();
let ID = this.elements.AB.value;
const APP = document.getElementById('app');
switch (ID) {
case 'A':
APP.innerHTML = 'HELLO BITCHES - #app is gutted by .innerHTML - everything within #app is overwritten';
break;
case 'B':
const htmlString = 'HELLO BITCHES - this is added in front of #app - nothing is overwritten bitches';
APP.insertAdjacentHTML('beforeBegin', htmlString);
break;
default:
break;
}
eventLogger(e);
};
function clicker(e) {
document.forms[0].AB.value = e.target.id;
};
function eventLogger(e) {
let ID = e.target.elements.AB.value;
console.clear()
let log = 'Event Type: ' + e.type + '\nEvent Listener ID: ' + e.currentTarget.id + '\nButton ID: ' + ID + '\nDefault Prevented: ' + e.defaultPrevented;
console.log(log);
};
body {
padding: 8px;
font: 1ch/1 Consolas;
}
h1 {
font-size: 1.75ch/1;
}
#app {
margin: 8px;
padding: 20px;
outline: 3px dashed blue;
}
form {
padding: 20px;
outline: 3px dotted red
}
input {
display: inline-block;
width: 15ch;
}
button {
display: inline-block;
width: 6ch;
cursor: pointer;
}
p {
display: inline-block;
}
p:first-of-type {
color: blue;
}
p:last-of-type {
color: red;
}
code {
font-weight: bold;
color: #ab00ef;
}
/* SO Console Display - Right Side Column */
.as-console-wrapper {
width: 50% !important;
max-height: 100%;
margin: 0 0 25% 50%;
font-size: 0.8ch/1;
font-variant: normal;
}
.as-console-row.as-console-row::after {
content: '';
padding: 0;
margin: 0;
border: 0;
width: 0;
}
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body class="body">
<h1>Vaccination Centers</h1>
<p>Blue dashed outline is <code>#app</code></p>
<p>Red dotted outline is <code>#form</code></p><br>
<div id='app'>
<form id='form'>
<input type="text" id='enrollment'>
<input type='text' id='session'>
<button id='A'>A</button>
<button id='B'>B</button>
<input id='AB' type='hidden'>
</form>
</div>
</body>
</html>
There were a few bits that needed some attendence:
In your original script you used an asynchronous fetch to define the variable listArray. Unfortunately you did not wait for the value to be put into that variable but continued straight away. This "awaiting" can only happen in an asynchronous function. Therefore:
I created an async function as this makes it much easier to process promises with await inside.
The first one fills listArray with all the registered students for comparison with an entered name
The comparison needs to be done on enrollment.value.trim().toLowerCase() (there is no .toString() involved)
If the name was found, a second fetch() command is sent, "PATCHing" the new information to the server
The return data from the server is then displayed in JSON format under the "success message".
const api='http://jsonplaceholder.typicode.com/users/';
document.getElementById('form').addEventListener("submit",validate);
async function validate(e) {
e.preventDefault();
const listArray=await fetch(api).then(r=>r.json());
let student= listArray.find(s=>s.username.toLowerCase()===enrollment.value.trim().toLowerCase())
if (student) {
const d = await fetch(api+student.id, {method: 'PATCH',headers: {'Content-Type': 'application/json'},body: JSON.stringify({paidFee:true})}).then(r=>r.json());
document.getElementById('app').innerHTML = '<div>HELLO BITCHES</div><pre>'+JSON.stringify(d,null,2)+'</pre>';
} else console.log("This student does not exist in our list: "+listArray.map(s=>s.username).join(" "));
}
<h1> Vaccination Centers</h1>
<div id='app'>
<form id='form'>
<input type="text" id='enrollment' value="Bret">
<input type='text' id='session'>
<button type="submit">submit</button>
</form>
</div>

How can I get a div to change its background-image after a specific event has taken place?

I have made a game using JavaScript and I would like the background to change after the game is over or after isGamerOver = true to be more specific. Here is what I currently have. Right now when ever the game ends I get a Uncaught TypeError: Cannot read property 'style' of null.
function gameOver() {
console.log('game over')
isGamerOver = true
while (grid.firstChild) {
grid.removeChild(grid.firstChild)
}
grid.innerHTML = score
clearInterval(upTimerId)
clearInterval(downTimerId)
clearInterval(leftTimerId)
clearInterval(rightTimerId)
if(isGamerOver = true){
document.getElementById("grid").style.backgroundImage="url('backgrounds/background-up.png')";
}else{
document.getElementById("grid").style.backgroundImage="url('backgrounds/game-over.png')";
}
}
Here is the style sheet I am trying to change
.grid {
width: 400px;
height: 600px;
background-image: url(backgrounds/background-up.png);
position: relative;
font-size: 100px;
text-align: center;
color: #fff;
}
Here Is my HTML
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>100% Not Doodle Jump</title>
<link rel="stylesheet" href="style.css"></link>
<script src="app.js" charset="utf-8"></script>
</head>
<body>
<div class="grid"></div>
</body>
</html>
I also added a div in JavaScript
const grid = document.querySelector('.grid')
const doodler = document.createElement('div')
If you got your grid defined like that:
const grid = document.querySelector('.grid')
change this:
if(isGamerOver = true){
document.getElementById("grid").style.backgroundImage="url('backgrounds/background-up.png')";
}else{
document.getElementById("grid").style.backgroundImage="url('backgrounds/game-over.png')";
}
to this:
if(isGamerOver = true){
grid.style.backgroundImage="url('backgrounds/background-up.png')";
}else{
grid.style.backgroundImage="url('backgrounds/game-over.png')";
}

TypeError: Cannot read property 'target' of undefined for event.target in event listener

So I have this code
I am trying to log the hex value to the console outside of the function.
when I put the console.log inside the function like so console.log(updatedColor); before the function closing it works.
the error I'm getting is:
Uncaught TypeError: Cannot read property 'target' of undefined
at updateFirst1 (script.js:15)
at script.js:21
updateFirst1 # script.js:15
(anonymous)
line 15 is chosenColor.style.backgroundColor = event.target.value; and line 21 is the console log.
var colorSelect;
window.addEventListener("load", startup);
function startup() {
colorSelect = document.querySelector("#color-picker");
colorSelect.addEventListener("input", updateFirst1);
colorSelect.select();
}
function updateFirst1(event) {
var chosenColor = document.querySelector(".colored-box");
if (chosenColor) {
chosenColor.style.backgroundColor = event.target.value;
}
var updatedColor = event.target.value;
return updatedColor;
}
console.log(updateFirst1());
#colored-box {
width: 700px;
height: 300px;
border: 1px solid;
}
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="colored-box" id="colored-box"></div>
<label for="color-picker">Color:</label>
<input type="color" value="#ff0000" id="color-picker">
<script src="script.js"></script>
</body>
</html>
The problem here is you are calling your updateFirst function manually outside of your event, so the event object is undefined and you are getting an error. When the console.log() is inside of the function, the event is defined as it is called from the input listener you added in your startup function.
you need to use log the result just when color is picking so just use console.log inside the function updateFirst1
Code:
var colorSelect;
window.addEventListener("load", startup);
function startup() {
colorSelect = document.querySelector("#color-picker");
colorSelect.addEventListener("input", updateFirst1);
colorSelect.select();
}
function updateFirst1(event) {
var chosenColor = document.querySelector(".colored-box");
if (chosenColor) {
chosenColor.style.backgroundColor = event.target.value;
}
var updatedColor = event.target.value;
console.log(updatedColor);
}
#colored-box {
width: 700px;
height: 300px;
border: 1px solid;
}
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div class="colored-box" id="colored-box"></div>
<label for="color-picker">Color:</label>
<input type="color" value="#ff0000" id="color-picker">
<script src="script.js"></script>
</body>
</html>

SetTimeout executing but no delay

I am developing a Binary Tree Search visualization program using JSAV library. The problem is that all the nodes are getting highlighted instantly and I want to show it step by step without any pressing of button again and again.
I tried to highlight a node and use timeout function to stop the execution for few seconds and then unhighlight the node and then proceed with next selected node, however there is no effect at all. Can anybody suggest me what can I do to modify my program to incorporate this type of feature?
Code: (Uses JSAV library)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/JSAV.css" type="text/css" media="screen" title="no title" charset="utf-8" />
<title>Test Binary Tree Page</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="lib/jquery.transit.js"></script>
<script src="lib/raphael.js"></script>
<script src="lib/JSAV.js"></script>
<Script src="lib/includeall.js"></Script>
<style>
.highlight
{
background-color: blue;
}
.unhighlight
{
background-color: white;
}
#av {
width: 98%;
position: relative;
}
.jsavcounter {
position: absolute;
top: 15px;
}
.jsavtree {
position: relative;
width: 500px;
height: 300px;
}
svg {
height: 600px;
}
path {
pointer-events: visible;
}
</style>
</head>
<body>
<div id="av">
</div>
<script>
var jsav=new JSAV("av");
var bt=jsav.ds.binarytree();
addNode(bt,20);
addNode(bt,5);
addNode(bt,40);
addNode(bt,50);
addNode(bt,60);
addNode(bt,70);
addNode(bt,4);
function donothing()
{
}
function searchBinarytree()
{
var value=parseInt(document.getElementById("value").value);
var test=bt.root();
while(test!=null)
{
test.addClass("highlight");
setTimeout(donothing,20000);
if(test.value()==value)
{
break ;
}
if(test.value()<=value)
{
test.toggleClass("unhighlight");
test=test.right();
}
else
{test.toggleClass("unhighlight");
test=test.left();
}
bt.layout();
}
}
</script>
<div id="valuebox">
Value to search:<input id="value" type="text"> <button type="button" onclick="searchBinarytree()"> Search</button>
</div>
</body>
</html>
setTimeout is calling donothing which is "doing nothing". You should instead call the function you want repeated from within setTimeout. I assume you expect it to pause at that call, but that's not how setTimeout works. More info can be found at https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout
Something like this should work (not tested)
var test;
function searchBinarytree() {
test = bt.root();
test.addClass("highlight");
setTimeout(updateNode, 20000);
}
function updateNode() {
var value = parseInt(document.getElementById("value").value);
if (test != null) {
if (test.value() != value) {
test.removeClass("highlight");
if (test.value() <= value) {
test = test.right();
} else {
test = test.left();
}
if (test != null) {
test.addClass("highlight");
}
setTimeout(updateNode, 20000);
}
bt.layout();
}
}
Not really sure that it's your issue but:
When you use setTimeout use it like that
setTimeout(yourFunction, timeout);
not
setTimeout(yourFunction(), timeout);
you have to pass the function to be invoked, you don't invoke the function

How to display javascript variables

I have looked up a question on the website (How to display javascript variables in a html page without document.write)
But when executing it in my own coding program it does not work. Hope you can help out!
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-1.11.3.js"></script>
<meta charset ="UTF-8">
<meta name="viewport" content="width=device-width">
<style type="text/css">
html {
font-family: sans-serif;
font-size: 16px;
}
h1 {
margin: 1em 0 0.25em 0;
}
input[type=text] {
padding: 0.5em;
}
.jsValue, .jqValue {
color: red;
}
</style>
</head>
<body>
<!-- This <input> field is where I'm getting the name from -->
<label>Enter your name: <input class="name" type="text" value="World"/></label>
<!-- Plain Javascript Example -->
<h1>Plain Javascript Example</h1>Hello <span class="jsValue">World</span>
<!-- jQuery Example -->
<h1>jQuery Example</h1>Hello <span class="jqValue">World</span>
<script>
//https://stackoverflow.com/questions/9689109/how-to-display-javascript-variables-in-a-html-page-without-document-write
// Plain Javascript Example
var $jsName = document.querySelector('.name');
var $jsValue = document.querySelector('.jsValue');
$jsName.addEventListener('input', function(event)){
$jsValue.innerHTML = $jsName.value;
}, false);
</script>
</body>
</html>
Because you have syntax error.. check the console.
Correct code should be:
$jsName.addEventListener('input', function(event){
$jsValue.innerHTML = $jsName.value;
}, false);

Categories

Resources