So, I'm trying to make a dice roller that can, you guessed it!, roll dice. I want to call a javascript function within a HTML button click. I know this is very easy with angular, but I am not using Angular. I am using jQuery, but I don't want to make the whole thing jQuery, however, if I have to, I will. Anyway, I am trying to make a button that adds a die, one that removes a die, one that adds a side to the dice, and one that removes a side from the dice. Oh, and one that rolls the dice, but I've already coded that in.
Here's my HTML (note: I am using jQuery so it might look a little weird):
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
$("#button0").click(function(){
diceRoll = 0
for (i=diceAmt;i>0;i--) {
diceRoll += rand(1, diceSides)
}
document.getElementById("dieRoll").innerHTML = diceRoll;
})
</script>
</head>
<body>
<div class="screen">
<div class="top">
<div class="text">
<span id="dieRoll"></span>
</div>
<button class="button1" id="button0"></button>
</div>
<div class="bottom">
<button class="button2">Add die</button>
<button class="button3">Remove die</button>
<br/>
<button class="button2">Add side</button>
<button class="button3">Remove side</button>
</div>
</div>
</body>
</html>
Here's my JavaScript (again might look a little weird):
var diceAmt = 2
var diceSides = 6
var diceRoll
var xDx = diceAmt+"d"+diceSides
function floor(num){let n1=Math.round(num);let n2=n1-1;if(n1>num){return n2}else{return n1}}
function rand(num1,num2){let n1=num2+1-num1;let n2=floor(Math.random()*n1)+num2;return n2}
function addDie () {
diceAmt += 1
xDx = diceAmt+"d"+diceSides
document.getElementById("button0").innerHTML = "Roll "+xDx
}
function rmoveDie () {
diceAmt -= 1
xDx = diceAmt+"d"+diceSides
document.getElementById("button0").innerHTML = "Roll "+xDx
}
function addSide () {
diceSides += 1
xDx = diceAmt+"d"+diceSides
document.getElementById("button0").innerHTML = "Roll "+xDx
}
function rmoveSide () {
diceSides -= 1
xDx = diceAmt+"d"+diceSides
document.getElementById("button0").innerHTML = "Roll "+xDx
}
Now, I would normally show you my CSS here, but the CSS doesn't matter.
Oh, I almost forgot to show you the libraries I'm using. Here they are:
jquery.js
I would really like it if you could help me out here.
Thank you!
(Note: I would normally do that part in code but I figured it would be cooler if it was an actual h1.)
Whenever a button is triggered a click event is fired. To handle that event there are 3 ways in vanilla javascript:
1. Specifying the function to be called in an HTML tag.
<button class="button2" onclick="addDie()">Add die</button>
2. Adding a handler in the button onclick property in JS.
const button = document.getElementById("your_button_id");
button.onclick = function(event) {
// do something
}
// or in your case
button.onclick = addDie
3. Adding an event listener
With this approach, you can add any number of handler for your event in the button.
button.addEventListener("click", addDie);
button.addEventListener("click", dieRoll);
These three are the possible ways to handle the events using vanilla JS.
Since you are using jquery you can simply do,
$("#button2").click(addDie)
To make sure the events are attached safely you would need to wait till the document is loaded.
1. In Jquery
$( document ).ready(function() {
...
$("#button2").click(addDie)
...
}
2. In Vanilla JS
document.addEventListener("DOMContentLoaded", function(){
...
button.addEventListener("click", addDie);
button.addEventListener("click", dieRoll);
...
});
Knowing the above three ways will help you understand the ways events can be handled with vanilla js.
Based on the code you showed, I think the issue is that your script is in the head part, before the body (including the buttons) is even loaded.
That means that when you do $("#button0"), you get a collection of zero elements (the buttons don't exist yet), and then you attach a click handler to zero elements, so you are doing nothing.
The solution is simple: jQuery allows you in a very simple way to defer the execution of some code until the DOM has finished loading. That is done by calling $ as a function and passing a callback, i.e. $(...) (or, more verbosely, by writing $(document).ready(...)):
$(function () {
$("#button0").click(function(){
diceRoll = 0
for (i=diceAmt;i>0;i--) {
diceRoll += rand(1, diceSides)
}
document.getElementById("dieRoll").innerHTML = diceRoll;
})
})
That should fix the issue.
Related
Hi great coding community,
I was struggling here for the whole weekend with this question in my head. I am trying to call a function within document.getElementBy... element but I am still getting undefined output. Well, I got the output from the function, but only if I put there a return value into the LoginFunction(). Otherwise only undefined.
But problem is, that this function is not returning anything. I'm just creating the buttons with it. (Maybe it should return something, but I designed it so poorly :D)
Anyway, my aim is to create a buttons into newly created div tag. I know that with return value (at least with simple text) it works. I got text within the new div. But without return value, nothing happened. And I tried these options:
// creating div, with id or with class - doesnt matter.
global_div = document.createElement("div");
// global_div.classList.add("two");
global_div.id = "two";
// appending it into the body.
document.body.appendChild(global_div);
// now calling the function:
document.getElementById('two').innerHTML = LoginFunction();
document.getElementsByClassName('two')[0].innerHTML = LoginFunction();
document.getElementById('two').call = LoginFunction();
document.getElementsByClassName('two')[0].call = LoginFunction();
document.getElementById('two').innerText...
document.body.appendChild(global_div);
and other options, versions, combinations... nothing helped.
The LoginFunction() is:
function LoginFunction() {
console.log("LoginFunction called")
var myLoop_var;
let outcome;
<!-- START BUTTON -->
let btn = document.createElement("button");
btn.innerHTML = "START";
btn.id = "start";
document.body.appendChild(btn);
btn.addEventListener("click", function () {
btn.disabled = true;
btn2.disabled = false;
console.log("START BUTTON clicked");
clearInterval(global_var);
global_var = setInterval(function(){myLoop()}, 1000);
console.log('MY LOOP VAR: ', global_var);
});
}
There are two other buttons with more less same code. So I am waiting for the click on the buttons. So basically they are not returning anything.
And in short, I want to click on one button which create a three new buttons in one div. Then, when I click on the same button, all three buttons are removed together with created div.
I would be really appreciating if somebody could give me a hint or lead me on the right way with this.
Many thanks to all of you. :)
ok sorry, that's my poor explanation skill as well. Pictures maybe helped more.
This is start:
This is after buttons are created:
And my dreamed result:
<div id="two">
<button id="start">START</button>
<button id="stop" disabled="">STOP</button>
<button id="stop" disabled="">STOP</button>
</div>
No, you can not call function with innerHTML as you are doing.
As per your way, innerHTML means you need to provide whole HTML string with all three buttons inclued which should be returned by function.
e.g
Elem.innerHTML = func()
func(){
return "<HTML string with all buttons tag />"
}
Another way, when you click on button, just call your function which perform adding of all buttons in parent div and append it, so you won;t bother about innerHTML or return values.
e.g
onclick="func()"
func(){
div_elem.append(buttons) // on innerHTML
}
If the question's cryptic to you then imagine how it is to me. I'm not even sure what to look up to begin with.
Anyway, I'm making a to-do list and have just about everything else done, but I'm supposed to:
Update the click code of adding the item to the list, not only should it add the text, it should also add a textarea and a button. (Figured this out myself.)
Give this textarea and button a CLASS. (Easy.)
Once you have appended the textarea and button, along with the to-do text to the list, you can now give the button a click handler. (Wait, doesn't it already have one?)
This click handler will get the value of the textarea (from step 1) and then replace it with the existing item. (What?)
Yes, it's help with homework; please don't throw rotten produce at me. Collaboration's allowed, as is pasting code so long as it isn't done blindly (i.e., I pull something from the web and have to ask why it still doesn't work).
Moving on, I asked the teacher what existing item he meant:
We have a button that creates list items, each of which has a button that lets you delete it. But I don't know about any "update" buttons; and why would need an extra function to replace text when each list item is already an updatable text box?
To which he said:
The reason for the extra update function is because the data in the text box does not exist in JavaScript, only in that text box, by making the update button pull the text from the text box we now have that text in JavaScript. While our simple app does not save any data, it's best practice to have data flowing from and to JavaScript, even though our app doesn't "need" it. The HTML and CSS is really only a simple interface that visitors can interact with, but JavaScript is how data is handled in the front-end.
I know the answer is just a few simple lines of code that I'll feel real dumb for not having figured out myself, but I don't want to spend hours on something so small because "suffering builds character." What can I do to make the program work as instructed? And how can I get better at figuring it out myself quickly?
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>To-Do List Front-End App</title>
<meta name="description" content="A to-do list app.">
<meta name="author" content="">
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<style>
/*vvvvvvvv CSS GOES BELOW THIS COMMENT vvvvvvvv*/
#list-header {
background-color: #e6e6fa;
}
#list-content {
background-color: #bf94e4;
}
/*^^^^^^^^ CSS GOES ABOVE THIS COMMENT ^^^^^^^^*/
</style>
</head>
<body>
<!-- vvvvvvvv HTML GOES BELOW THIS COMMENT vvvvvvvv -->
<div id="list-header">
<h1>To-Do List</h1>
</div>
<div id="list-content">
<form>
<p>New Note: </p>
<textarea id="new-note"></textarea>
</form>
<button id="submit-note">Create To-Do Item</button>
<ul id="list">
</ul>
</div>
<!-- ^^^^^^^^ HTML GOES ABOVE THIS COMMENT ^^^^^^^^ -->
<script>
/*global $*/
/*vvvvvvvv JAVASCRIPT GOES BELOW THIS COMMENT vvvvvvvv*/
$(document).ready(function () {
$("#new-note").keypress(function (event) {
if (event.which == 13) { // Enters new list item when you press Return/Enter
event.preventDefault();
var noteText = $("#new-note").val();
$("#list").append("<li>" + "<textarea class='notes'>" + noteText + "</textarea>" + " <button class='remove'>Delete</button></li>");
$(".remove").click(function () { // Removes list item when you press the Delete button.
$(this).parent().remove();
});
$("#new-note").val(""); // Blanks the text area when you enter an item.
} // <- An IF statement, not a function
});
$("#submit-note").click(function () { // Enters a new list item when you click Create To-Do Item back in the HTML.
var noteText = $("#new-note").val();
$("#list").append("<li>" + "<textarea class='notes'>" + noteText + "</textarea>" + " <button class='remove'>Delete</button></li>");
$(".remove").click(function () {
$(this).parent().remove();
});
$("#new-note").val("");
});
});
/*^^^^^^^^ JAVASCRIPT GOES ABOVE THIS COMMENT ^^^^^^^^*/
</script>
</body>
</html>
Assuming your teacher simply wants you to grab the value of the textarea by clicking a button, you would do something like this in javascript. I'll leave you up to thinking of how to do it with jQuery.
The html
<textarea id="textarea">Blah blah blah</textarea>
<button id="btn">Get textarea</button>
The JS
var textarea = document.getElementById('textarea');
var btn = document.getElementById('btn');
btn.addEventListener('click', function () {
console.log(textarea.value);
})
// The better way to do it as requiring the user to click a button is just....rediculous
// but perhaps you haven't learned about events yet.
textarea.addEventListener('change', function (e) {
console.log(e.target.value);
})
https://jsfiddle.net/jamesbrndwgn/f9zb5rm7/4/
EDIT
Based on clearer requirements in comment.
Your#1 - Add a text area, and add an update button;
Your#2 - attach click handler to update button;
Your#3 - this handler will take the value of the text area created in step
1);
Extra step - Let the user modity the text.
Your#4 - use this value and replace the existing list item text;
Your#5 - the update should empty out text area.
Here is the code you need.
$(document).ready(function () {
$("#new-note").keypress(function (event) {
if (event.which == 13) {
event.preventDefault();
var noteText = $("#new-note").val();
var listItem = "<li>" + noteText + " <button class='remove'>Delete</button><button class='update'>Update</button></li>";
$("#list").append(listItem);
$("#new-note").val("");
}
});
$("#submit-note").click(function () {
var noteText = $("#new-note").val();
var listItem = "<li>" + noteText + " <button class='remove'>Delete</button><button class='update'>Update</button></li>"; // Your #1
$("#list").append(listItem);
$("#new-note").val("");
});
//
// Button handlers using delegation (since those are dynamically created)
//
// REMOVE
$("#list").on("click",".remove",function () {
$(this).parent().remove();
});
// UPDATE
$("#list").on("click",".update",function () { // Your #2
var thisListItem = $(this).parent();
thisListItem.find("button").remove();
var thisListText = thisListItem.text().trim(); // Your #3
var newTextarea = $("<textarea>").text(thisListText);
thisListItem.empty().append(newTextarea).append(" <button class='updateOk'>Ok</button>"); // Needs two append. One for the jquery object and one for a string
});
// UPDATE OK
$("#list").on("click",".updateOk",function () {
var thisListItem = $(this).parent();
var thetextareaVal = thisListItem.find("textarea").val();
thisListItem.empty().append(thetextareaVal + " <button class='remove'>Delete</button><button class='update'>Update</button>"); // Your #4
});
}); // END ready
In the code above, you'll find "Your #n" 1 to 4. The #5 is achieved by .empty() two places, before and after user action.
The "extra step" occurs between the two update handlers... Because that needs an extra "ok" button... That's why it's 2 handlers.
That is all about event handlers...
You are dealing with dynamically created buttons, so again... Make sure to do at least the minimal reading about delegation.
Delegation in short (and in my words): Normally, the code will only apply only on existing elements (in the DOM) when the script is parsed. The only way around for this big problem is delegation.... That is about to attach the handlers needed for future element on a STATIC parent... The result is this static element WILL "distribute" the event on its matching child, if it has any when the event occurs.
To define an event handler within another is a bad practice. Please stop that now and forever. If you continue to do so anyway because it works... You will sooner or later encounter some strange behaviors sometimes hard to narrow down. Examples
And never loop over a handler definition. Loop over the HTML markup to add and give it classes already defined once. -- One class, one handler. Many events on a class can be one handler.
Beyond that, it only about to get/set values and replace/overwite/create elements.
A working demo is avalable here: Your JsFiddle updated.
I'm developing a custom ordering process and I'm using AJAX requests and dynamic forms a lot to complete parts of the ordering process, but I'd like to cleanup the way I'm doing it into terms of the HTML. I'm using jQuery too.
In looking at applications like Google's word processor, I can see that both the DOM and source exhibit no javascript event attributes. For example:
<div id="docs-file-menu" role="menuitem" class="menu-button goog-control goog-inline-block" aria-disabled="false" aria-expanded="false" aria-haspopup="true" style="-webkit-user-select: none;">File</div>
My guess is that a script is registering Javascript events after the fact based on the HTML attributes.
My website is much less complex, but I was wondering how to approach this as I currently have button styled <a><img></a> tags (or similar) that call Javascript functions, which works fine, but seems like the lesser (and old school) approach. For example:
<a href="javascript:Customisation.beginNewPair()">
<img src="images/begin-new.gif" />
</a>
Here is a simple example on how to use data attributes and an eventListener on click:
var a = document.getElementById('docs-file-menu');
a.addEventListener('click', test);
function test () {
var dis = a.getAttribute('aria-disabled');
var exp = a.getAttribute('aria-expanded');
var has = a.getAttribute('aria-haspopup');
if (dis == 'true') {
alert('disabled = true');
}
if (exp == 'true') {
alert('expanded = true');
}
if (has == 'true') {
alert('haspopup = true');
}
}
You also could access the different data attributes on page load and, according to them, you could be running different functions.
Here's a simple DEMO with onclick event, simply click on File
What you want is addEventListener.
How you access the elements is another question, but say you want an alert every time somebody clicks on a box.
var box = document.getElementById('box');
box.addEventListener('click', function(){ alert(); });
<div id="box" style="width:150px;height:150px;background:blue;"></div>
You can also put what happens in a real function:
function doSomething(){
alert();
}
var box = document.getElementById('box');
box.addEventListener('click', doSomething);
<div id="box" style="width:150px;height:150px;background:blue;"></div>
As of right now, I am able to get this javascript function to work with one link.
However, I would like to use the function with multiple links. I have changed obj to different values and have also tried using more than one function specified with different values for each to get a working prototype, but nothing seems to work. Below is the javascript function from scratch, no changes.
<script type="text/javascript">
function gObj(obj) {
var theObj;
if(document.all){
if(typeof obj=="string") {
return document.all(obj);
}
else {
return obj.style;
}
}
if(document.getElementById) {
if(typeof obj=="string") {
return document.getElementById(obj);
}
else {
return obj.style;
}
}
return null;
}
</script>
And the link code:
<div id="axphsh">
<b>Phone:</b><a href="#" onClick="
gObj('axphsh').style.display='none';
gObj('axphhd').style.display='block';
return false;">Click for Phone Number</a></div>
<div id="axphhd" style="display:none">
<b>Phone:</b> 555-555-5555</div>
Ultimately what I want is to use the link code for multiple numbers on the same page, all hidden by default, then unhidden onClick. But like I said, this only works for one phone number link, then if there are more specified on the same page, the onClick event doesn't work at all. I am thinking it has to do with getElementById since div ids for links can be specified in that manner, but I am not completely sure.
You should learn some basic JS DOM manipulation.
Why do you even use document.all which is not a part of the standard? Use document.getElementyById or document.querySelector.
If all of your boxes with phone numbers were similar you could go with a more general function:
HTML:
<div class="phone-link-container">
Click for phone number
</div>
<div class="phone-number-container">555-555-555</div>
JS:
function showNumber (e) {
var link = e.target,
link_container = e.target.parentNode,
phone_number = link_container.nextElementSibling;
link_container.style.display = 'none';
phone_number.style.display = 'block';
}
var numbers = document.querySelectorAll('.show-phone-number');
Array.prototype.forEach.call(numbers, function (el, i) {
el.addEventListener('click', showNumber);
});
It selects all elements with a class show-phone-number and binds a function showNumber to the click event for each of them. This function hides parent of the link (which would be phone-link-container in my example) and shows next sibling of the parent (which is phone-link-container).
http://jsfiddle.net/9ZF9q/2/
In case your JavaScript code is in head you need to wrap all DOM manipulations inside window load callback:
window.addEventListener("load", function () {
var numbers = document.querySelectorAll('.show-phone-number')
Array.prototype.forEach.call(numbers, function (el, i) {
el.addEventListener('click', showNumber);
});
});
You can read more on functions used there on https://developer.mozilla.org/en-US/docs/DOM/Element.nextElementSibling
When it comes to DOM manipulation if you want to keep the compatibility with all older browsers it's easier to use jQuery library - especially if you're a beginner.
I've got a long running method -- and I want to indicate to the user that an operation is underway. This is NOT and ajax call, so I can't use the common pattern I've used in the past to display, say a spinner, before the ajax event, then hiding it on success for example.
In my case -- I'm not making an ajax call, I'm instead doing some very heavy DOM manipulation.
I had a test example on jsFiddle.net -- would love to learn how to capture the event. At the moment, my "wait-message" div updates at the same exact time when my operation completes which is much too late :(
Complete sample code is here: http://jsfiddle.net/rsturim/97hrs/6/
Javascript (jQuery)
$(document).ready(function() {
$("#link-action").click(function(e) {
$("#wait-message").text("starting ...");
var count = longRunningMethod(1000000000);
$("#result").text(count);
$("#wait-message").text("completed.");
});
var longRunningMethod = function(countUpTo) {
var i = 0;
while (i <= countUpTo) {
i++;
}
return i;
};
});
HTML:
<div id="wait-message">
push button please
</div>
<hr />
<button id="link-action">Run Operation</button>
<hr />
<h1>Results:</h1>
<div id="result"> </div>
Here is a solution. I'm not sure if it works in all browsers, you may want to test it out in several, but I think it does:
$(document).ready(function() {
$("#link-action").click(function(e) {
$("#wait-message").text("starting ...");
// Stuff to do after a render
setTimeout(function(){
var count = longRunningMethod(1000000000);
$("#result").text(count);
$("#wait-message").text("completed.");
}, 0);
});
var longRunningMethod = function(countUpTo) {
var i = 0;
while (i <= countUpTo) {
i++;
}
return i;
};
});
Basically, the browser won't render any changes until a script finishes executing. That allows you to do things like:
Hide all divs with a certain class
Show one of those divs
In a row and the browser will never render the div that is being shown as hidden, so you won't get weird flickers or things moving around on the page.
Using setTimeout like I did, the anonymous click handler will finish executing, the browser will re-render, the the anonymous function in the setTimeout will run (immediately after the render since there is no actual delay).
Use setTimeout or setInterval instead of your while loop; a sub-second delay like 15ms should be enough to prevent your window freezing / UI locking.