Is it possible to stop the script and wait for user input before continuing it?
Here is the portion that I need to stop:
var nName = document.getElementById("b1");
nName.innerHTML = "Continue";
document.getElementById("b1").onclick = newName();
So "b1" is a HTML button, I want to stop it after
nName.innerHTML = "Continue";
and wait for user click on the button before firing
document.getElementById("b1").onclick = newName();
using return completely stop the script. Is there any other possible way to do this?
You do not need to stop the script. You cannot.
Pass references to the functions (no paranthesis on the function names) like so:
document.getElementById("b1").onclick = newName;
Example:
function firstClick(){
document.getElementById('b1').innerHTML = "Continue"
// override the first click listener. "firstClick" will no longer be called.
document.getElementById('b1').onclick = newName;
}
function newName(){
document.getElementById('b1').innerHTML = "Good Job!"
}
// listen for first click
document.getElementById('b1').onclick = firstClick
<button id=b1>Click Me!</button>
In order to fully understand what is going on, I do must refer you do Google and Documentation, and most of all - Experimentation.
But in short, in not technical terms.
onclick does nothing on its own. It needs to be told what it does. The browser will do what you tell it to. There can only be 1 function assigned to it. So if you do onclick=a; onclick=b; onclick=c, only c will be called.
If you assign the function name with paranthesis onclick = newName(), what you are doing is you are running the newName() and assigning its return to the onclick. So in this case - nothing. If you do onclick=newName the borwser will automatgically add the paranthesis.
You could even create a 'triaging' function to decide what the next steps are:
function triage(){
var el = document.getElementById('b1');
if (el.innerHTML == "Continue"){
el.innerHTML = 'Good Job!';
}else{
el.innerHTML = 'Continue';
}
}
// listen for first click
document.getElementById('b1').onclick = triage
<button id=b1>Click Me!</button>
Related
I am trying to write a simple banking app to learn basic DOM manipulation stuff. This will be a single page website with lots of function calls and hiding/displaying containers.
Once I click the register button on the main screen, it calls registerScreen() function which then hides the main screen elements and shows a form group with text boxes and a submit button that saves the filled in information. However, saveCustomer() function calls itself as soon as I bring up the register screen. Obviously, it submits a blank form which is a problem.
I have tried different event listener methods like submit, click, getElementById().onclick, and so on. I did not want to call saveCustomer() function on HTML because I do not know how I can pass the info with that approach.
function registerScreen() {
document.getElementById("welcome-container").style.display = "none";
document.getElementById("registerScreen").style.display = "block";
let customerFirstName = document.getElementById('firstName').value;
let customerLastName = document.getElementById('lastName').value;
let customerPassword = document.getElementById('password').value;
let randomID = document.getElementById("randomID");
let ID = Math.floor((Math.random() * 999) + 100);
randomID.innerHTML += ID;
//This is the line I am having problems with
document.getElementById("submitInfo").addEventListener("click", saveCustomer(ID, customerFirstName, customerLastName, customerPassword));
}
function saveCustomer (ID, customerFirstName, customerLastName, customerPassword) {
let customer = {
id: ID,
firstname: customerFirstName,
lastname: customerLastName,
password: customerPassword,
cashAmount: 0,
}
if (localStorage.getItem("customers") === null) {
let customers = [];
customers.push(customer);
localStorage.setItem("customers", JSON.stringify(customers));
} else {
let customers = JSON.parse(localStorage.getItem("customers"));
customers.push(customer);
localStorage.setItem("customers", JSON.stringify(customers));
}
alert("Registration successful.");
}
Try wrapping saveCustomer in an anonymous callback function like so:
document.getElementById("submitInfo").addEventListener("click", () => {saveCustomer(ID, customerFirstName, customerLastName, customerPassword)});
The issue is that you are not registering a function to be called when #submitInfo is clicked, but the event listener is malformed and you are calling another function from withing the declaration. Instead, you should register a new anonymous function when clicking #submitInfo and only call the saveCustomer() from withing that anonymous function.
Below is the wrong way that you are using in your case.
<button id="btn">Click</button>
<script>
document.getElementById("btn").addEventListener("click", alertSomething("test"));
function alertSomething(text) {
alert("Inside here, alerting "+text);
}
</script>
When initializing the eventListener, it is making a call to the alertSomething() function. This will trigger the alertSomething() function as soon as the document has loaded.
What you want instead is to define a new anonymous function that will get called once the button has been clicked and only call the alertSomething() function from inside this new function. It is called anonymous function because it doesn't have a name like an ordinary function.
The correct way to accomplish this:
<button id="btn">Click</button>
<script>
document.getElementById("btn").addEventListener("click", function() {
alertSomething("test")
});
function alertSomething(text) {
alert("Inside here, alerting "+text);
}
</script>
I'm new to javascript, and have a lot of confusions...
I'm trying to write a script in Tampermonkey which would allow to put the cursor at the end of the input area once "copy" event listener is triggered.
This is the site where I want to apply it: https://voicenotebook.com/#medtrdiv
The original code is:
var input = document.querySelector('#docel');
var textarea = document.querySelector('#docel');
var reset = function (e) {
var len = this.value.length;
this.setSelectionRange(len, len);
};
input.addEventListener('copy', reset, false);
textarea.addEventListener('copy', reset, false);
The problem is that if I click copy, it doesn't copy the text, though it puts the cursor at the end. So I guess the problem is that the function executes too soon.
I wanted to add some delay to this function, but nothing seems to work. So I think the solution would be to delay the function by 100ms once an eventlistener is triggered.
This is what I tried:
var input = document.querySelector('#docel');
var textarea = document.querySelector('#docel');
var reset = function (e) {
var len = this.value.length;
this.setSelectionRange(len, len);
};
textarea.addEventListener('copy', setTimeout(reset, 100), false);
input.addEventListener('copy', setTimeout(reset, 100), false);
I know this probably doesn't make sense at all. I've tried different things also. I've researched many topics about this, but nothing works for me. Can you please help me to figure it out?
Thank you in advance!
There are couple of issues in the code you have written.
id is supposed to be unique on the page.
You intent is to delay the setSelectionRange. This happens when the copy event is triggered. Move the setTimeout to inside the reset function.
Also you if you want to select the text from the start your first argument should be 0.
Your event gets triggered sometime in the future and wrapping reset function reference in the event handler really does nothing other than binding the event handler.
var input = document.querySelector('#docel1');
var textarea = document.querySelector('#docel2');
var reset = function(e) {
var context = this;
setTimeout(function() {
var len = context.value.length;
context.setSelectionRange(0, len);
}, 100);
};
input.addEventListener('copy', reset, false);
textarea.addEventListener('copy', reset, false);
<input id="docel1" />
<textarea id="docel2" />
I have a button on my website, which plays the music when you click on it and in the same time it changes the text inside of the button (to "Go to SoundCloud".)
I want that button (with the new text on it) to redirect to SoundCloud when I click on it.
Now I got both when click first time, which is redirect to SoundCloud and play the track. (plus it changes the text)
Any ideas, how to solve this problem? Thx!
var links = document.getElementById("playButton");
links.onclick = function() {
var html='<iframe width="100%" height="450" src="sourceOfMyMusic"></iframe>';
document.getElementById("soundCloud").innerHTML = html;
var newTexts = ["Go to SoundCloud"];
document.getElementById("playButton").innerHTML = newTexts;
newTexts.onclick = window.open('http://soundcloud.com/example');
};
Use a variable that indicates whether it's the first or second click.
var first_click = true;
links.onclick = function() {
if (first_click) {
// do stuff for first click
first_click = false;
} else {
// do stuff for second click
}
}
Just redefine the onclick after the first function call.
Put the onclick on the button instead of the html.
document.getElementById("playButton").onclick=window.open('http://soundcloud.com/example');
Another option in some cases is to use a ternary operator and a boolean toggle expression:
let btn = document.querySelector('.button');
let isToggledOn = false;
btn.addEventListener ('click', function(e) {
e.target.textContent = !isToggledOn ? 'Is ON' : 'Is OFF';
isToggledOn = !isToggledOn;
});
newTexts.onclick is not creating a function to open a window, it is simply taking the return value of window.open which is being executed right away.
It should look like:
newTexts.onclick = () => window.open('http://soundcloud.com/example');
Also this will not work as intended because newTexts is not the actual DOM element, you need to attach the new onclick on the element and not the array...
But to other answers in this page, the logic is hard to read, so I'd advise to refactor the logic to be more readable.
I'm writing a game using HTML5 canvas and Javascript. I'm using setInterval to animate the game and check for events at regular intervals. I've written multiple levels for the game, but I can't seem to escape the setInterval when a given level ends in order to start the next one. The code accurately detects when a level is won or lost and successfully clears the interval and renders the button, but the button does not fire.
Adding a button was my latest idea. I've also tried removing the canvas using jQuery and inserting a new one. I've also tried using clearRect on the canvas but it doesn't fire either.
Given that I can't return a value from setInterval, what are my options, if any? Is there another way to accomplish the same thing? Is there a separate error with my code that I've overlooked? Thanks!
Game.prototype.win = function(int) {
clearInterval(int);
var content = "<p style='color:white;'>You win</p><br><button id='next-level'>Next Level</button></menu>"
$('#controls').append(content)
};
Game.prototype.lose = function(int) {
clearInterval(int);
var content = "<p style='color:white;'>You Lose</p><br><button id='next-level'>Start Over?</button></menu>"
$('#controls').append(content)
};
Game.prototype.run = funtion () {
$('#start').click( function () {
$('#controls').empty();
var waveOne = new window.CrystalQuest.Wave(this.X_DIM, this.Y_DIM, this, Game.WAVE_ONE)
var game = this
var int = setInterval( function () {
if (waveOne.step() === "lost" ) {
game.lose(int);
} else if (waveOne.step() === "won") {
game.win(int);
}
waveOne.draw(this.ctx)
}, 20)
this.bindKeyHandlers(waveOne);
}.bind(this));
$('#next-level').click( function () {
$('#controls').empty();
...more code...
});
};
To stop a setInterval() you have to store the returned value from the original call to setInterval() in some persistent location and then call clearInterval() on that value.
Because you declared your interval with var as in var int, it was local only to that method and was not available anywhere else in the code.
There are a number of ways to do that in your code. I would probably suggest storing it as an instance variable like this:
Game.prototype.run = funtion () {
$('#start').click( function () {
$('#controls').empty();
var waveOne = new window.CrystalQuest.Wave(this.X_DIM, this.Y_DIM, this, Game.WAVE_ONE)
var game = this;
this.stop();
this.interval = setInterval( function () {
if (waveOne.step() === "lost" ) {
game.lose(int);
} else if (waveOne.step() === "won") {
game.win(int);
}
waveOne.draw(this.ctx)
}, 20)
this.bindKeyHandlers(waveOne);
}.bind(this));
$('#next-level').click( function () {
$('#controls').empty();
...more code...
});
};
Then, you can make a method that will stop the interval like this:
Game.prototype.stop = function() {
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
}
}
And, change your other methods like this:
Game.prototype.win = function(int) {
this.stop();
var content = "<p style='color:white;'>You win</p><br><button id='next-level'>Next Level</button></menu>"
$('#controls').append(content)
};
Game.prototype.lose = function(int) {
this.stop();
var content = "<p style='color:white;'>You Lose</p><br><button id='next-level'>Start Over?</button></menu>"
$('#controls').append(content)
};
For your event handling issues, if you are destroying and recreating a button, then you will lose any event handlers that were attached to any DOM elements that got replaced.
You have two choices for how to fix it:
After you create the new DOM elements, you can again set the event handlers on the new DOM elements.
You can use "delegated event handling". This attaches the event handlers to a parent DOM object that is itself not replaced. The click event bubbles up to the parent and is handled there. The child can be replaced as many times as you want and the event handler will still work.
See these references for how to use delegated event handling with jQuery:
Does jQuery.on() work for elements that are added after the event handler is created?
jQuery .live() vs .on() method for adding a click event after loading dynamic html
JQuery Event Handlers - What's the "Best" method
In my page there is a frame that belongs to the same domain. The content of this frame is varied and relatively unpredictable. Whenever a user clicks a button (inside the frame) that performs a post, I need to execute a function that performs some UI tasks. The problem is that I cannot edit the source of these frames for reasons beyond my control. Some of these buttons are simple form submit buttons, but others do not directly submit the form, but instead have an onclick handler that performs some checks and might submit.
Here is the problem: How do I detect if one of these onclick handlers called form.submit()? If there's no handler, then obviously I can set up a handler for onsubmit(), but is not the case for all of these buttons.
This is my code so far:
function addEventBefore(element, type, before, after) {
var old = element['on' + type] || function() {};
before = before || function() {};
after = after || function() {};
element['on' + type] = function () {
before();
old();//I can't modify this old onclick handler
after();
};
}
function setup() {
console.log('setup');
}
function takedown() {
// In this method, I want to know if old() caused a form submit
console.log('takedown');
}
function $includeFrames(jQuery, selector) {
return jQuery(selector).add(jQuery('iframe').contents().find(selector));
}
var a = $includeFrames($, 'input[type="submit"], input[type="button"]').each(function() {
var elem = $(this)[0];
addEventBefore(elem, 'click', setup, takedown);
});
In the onload event of the iframe you'll need to hook up an event listener to each form in the iframed page. You need to do this on every load, as each fresh page needs new listeners.
$("#someIframe").on('load',function() {
$(this).contents().find("form").each(function() {
$(this).on('submit',function() {... your code...})
})
}
The solution that worked for me came from a friend of mine. The solution is to shim the form.submit() function.
$(function() {
var el = document.getElementById('myform');
el.submit = function(fn) {
return function() {
myFunctionGoesHere();
fn.apply(this, arguments);
};
}(el.submit);
});
Here is a working example: http://jsfiddle.net/hW6Z4/9/