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.
Related
I am facing a very strange issue with the Selection API (https://developer.mozilla.org/en-US/docs/Web/API/Selection) on Chrome. I think I am using the API correctly, and tried different things but I always end up with the same outcome.
Considering the example HTML page below, with some static behaviour, the backwards selection doesn't work correclty: I always get the focus back to the right-most span element. (To get the Selection API running on this example, for a backwards selection, press the left key at the beginning of the right-most span element, the one with "abc..").
It doesn't seem to be something already mentioned on forums, so I must be doing something wrong but... I can't find out why. Firefox works as I expect: running that example, I get the caret and focus on the first span (the one with numbers).
Thanks a lot for your help!
<html>
<head>
</head>
<body>
<div id="parent1">
<span id="span0" contenteditable="true" onfocus="onFocus('span0')" onblur="onBlur('span0')">987654</span>
<span>+</span>
<span id="span1" contenteditable="true" onfocus="onFocus('span1')" onblur="onBlur('span1')">1234 6789</span>
<span>µ</span>
<span id="span2" contenteditable="true"onfocus="onFocus('span2')" onblur="onBlur('span2')">abcdefg</span>
</div>
<br><br>
<button onclick="doForwardSelection()">click</button>
<script>
span0 = document.getElementById("span0");
span2 = document.getElementById("span2");
function onFocus(id){
console.log("FOCUS on " + id);
}
function onBlur(id){
console.log("BLUR on " + id);
}
function doForwardSelection(){
docSel = document.getSelection();
// remove existing selection
docSel.removeAllRanges();
// set a new forward selection
docSel.setBaseAndExtent(span0.firstChild, 1, span2.firstChild, 2);
}
function onKeyDown(event){
//console.log(event);
if(event.key == "ArrowLeft" && document.getSelection().getRangeAt(0).startOffset == 0){
event.stopImmediatePropagation();
event.stopPropagation();
event.preventDefault();
// Do the selection manually
doMultiSelection();
}
}
function doMultiSelection(){
docSel = document.getSelection();
// first focus target
span0.focus();
console.log(docSel)
// then do the extent
console.log("I call Selection.setBaseAndExtent() now...")
//docSel.setBaseAndExtent(range.endContainer, range.endOffset, range.startContainer, range.startOffset);
docSel.setBaseAndExtent(span2.firstChild, 2, span0.firstChild, 1);
console.log(docSel);
}
document.getElementById("span2").addEventListener('keydown', onKeyDown);
</script>
</body>
</html>
So, I think I understand why what I tried didn't work.
The selection I want to make isn't in a single editable element (multiple spans), and their common ancestor isn't an editable element (div).
If I changed things by setting the div parent editable (contenteditable="true"), I can do the selection as I wanted to.
Based on the documentation on MDN, it may explain why Chrome behaved the way it did with my initial example.
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
}
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.
I am making a text adventure game, which would require user input in the form of a element in html, which would send the user input to JavaScript using the click function:
<!-- HTML CODE -->
<div class="game">
<div id="gamebox">
<a name="game"></a>
<!-- Javascript writes to here (if it works :( ) -->
</div>
<div id="inputbox">
<input type="text" id="userinput" placeholder="Input" value="" />
Go!
</div>
</div>
As you can see above, I have a element and a "Go!" button, which sends it to my JavaScript code. In JavaScript, first I define 3 variables where I would output my text.
//JavaScript Code
var txt_input = $("#userinput");
var btn_quest = $("#btn-quest");
I would than define 2 other functions, which allows me to write into the . I would than have other functions, which are for the storyline of the text adventure game. However, the root of the problem is that I can't seem to progress past the second event. Here are my events:
function wakeUp() {
displayGame("You wake up, at stackoverflow. West or east? [Choose 'west' or 'east']");
btn_quest.on({
"click": function() {
// Begin input preproccessing
var input = txt_input.val().toLowerCase();
// If/else block for choice here
if (input === "west") {
//Paste btn_quest here for new event
goWest();
} else if (input === "east") {
//Paste btn_quest here for new event
goEast();
} else {
//Error handler - do not modify
txt_input.val("Error - enter a valid choice");
}
//End of if else block body
}
});
The first event function would work perfectly, and write to my html, and accept the first user choice. However, at the next event, no matter what it is, (goEast() or goWest()), my program aways displays "Error - enter a valid choice"). Right now, my hypothesis is that the "switch" function isn't working correctly. However, I honestly don't know. What is the issue here, and how can I fix it? The other event functions (etc goEast) are exactly the same as the wakeUp function, except with different displayGame() strings and link to other event functions.
I have not included the full code, in order to keep my code short - but here is the full html/css/javascript if needed: http://plnkr.co/edit/55heHh4k5QEIVYdBrWGB?p=preview
Edit: I tried to implement the suggestion, like this: But It seems that JavaScript doesn't even get the userinput anymore. When I try to submit the user's response, nothing happens. What went wrong? I did the same thing here with all of my functions in the game:
function wakeUp() {
displayGame("You wake up at stackoverflow again, but it didn't work. Go West or east again?");
// btn_quest.off("click").on("click",function()){
btn_quest.off("click").on;
"click", function() {
// Begin input preproccessing
var input = txt_input.val().toLowerCase();
// If/else block for choice here
if (input === "walk") {
//Paste btn_quest here for new event
walkToWork();
} else if (input === "bus") {
//Paste btn_quest here for new event
busToWork();
} else {
//Error handler - do not modify
txt_input.val("Error - enter a valid choice");
}
//End of if else block body
};
//End of function. Copy until line under this comment V
}
What did I do wrong? Can you please show a example using this function?
You need to look at all the code to see the problem. The reason is because you keep binding to the element so multiple click events are being triggered. You need to remove the last click
btn_quest.off("click").on("click",function(){});
I am putting up a web site for a business and they want a page dedicated to their good reviews of their products.
They however don't want huge paragraphs taking up their page. Is there a way to make it so that for each review there is something they can click on, such as just a line of it, then "click here", that would expand each one individually?
I hade a gentlemen help me a little while back, but it only worked for one entry. I used the same javascript for all 3 and I am thinking that was incorrect.
Also, I am assuming this will expand the height of the page based on how long the review was. I only mention this because I have a footer at the bottom.
Anyway, JavaScript I assume?
<div class="comment">
This is the first line of the comment
<span id="extended_comment" style="display:none;">and this is the rest of the comment that is hiddden.</span> click here for more</div>
<script type="text/javascript">
var toggle = document.getElementById('toggle');
toggle.onclick = function() {
var extended = document.getElementById('extended_commen…
if(this.innerHTML == 'click here for more') {
extended.style.display = 'inline';
this.innerHTML = 'click here for less';
} else {
extended.style.display = 'none';
this.innerHTML = 'click here for more';
}
};
</script>
Encapsulate your code in a function and pass the necessary ids to that function in order to set each element's onclick property.
function setExpandOnclick(toggleButton, extendedComment) {
// your code here, using the arguments rather than hard-coded string ids
}
setExpandOnclick("toggle-button1", "expanded-comment1");
setExpandOnclick("toggle-button2", "expanded-comment2");
You were on the right track.