I have a button and empty div in HTML.
<button id="add_sentence">Click here!</button>
<div id="parent"></div>
In JS, I have data in array
let data = [{ sentence: "Hi, I'm from Azerbaijan" }, {sentence: "I'm 36 years old"}, { sentence: "I learn front-end development}]
I need a function that when I click on button ("#add_sentence"), it takes only one sentence from array ("data") and adds to div ("#parent").
I can add all array to empty div with 1 click. But I want 1st click adds 1st sentence. Then, 2nd click adds 2nd sentence. 3rd click adds 3rd sentence and so on.
Can anyone help?
let data = [{ sentence: "Hi, I'm from Azerbaijan" }, {sentence: "I'm 36 years old"}, { sentence: "I learn fron-end development"}];
const button = document.querySelector("#add_sentence");
const parent = document.querySelector("#parent");
let clickCount = 0;
button.addEventListener('click', () => {
if (clickCount < data.length) {
const nextSentence = document.createElement('p');
nextSentence.innerText = data[clickCount].sentence;
parent.appendChild(nextSentence);
clickCount++;
}
})
<button id="add_sentence">Click here!</button>
<div id="parent"></div>
Without clickcount...
var data = [{ sentence: "Hi, I'm from Azerbaijan" }, {sentence: "I'm 36 years old"}, { sentence: "I learn front-end development"}],
prnt = document.getElementById("parent"),
bttn = document.getElementById("add_sentence");
bttn.addEventListener("click", _ => data.length && (prnt.textContent += `${data.shift().sentence}
`));
#parent { white-space: pre;
}
<button id="add_sentence">Click here!</button>
<div id="parent"></div>
Related
I have a basic word scramble game (not styled yet), that works fine on an HTML page.
When I bring that exact code over to a blogger post it stops working.
I can enter text into the text field but on pressing the "Check Word" button it throws back a "Please enter the word to check" even though I have entered a word to check.
Everything else seems to work correctly on blogger (Refresh button, counter, hint, etc.)
The code is as follows...
let words = [
{
word: "addition",
hint: "The process of adding numbers"
},
{
word: "meeting",
hint: "Event in which people come together"
},
{
word: "number",
hint: "Math symbol used for counting"
},
{
word: "exchange",
hint: "The act of trading"
},
]
const wordText = document.querySelector(".word"),
hintText = document.querySelector(".hint span"),
timeText = document.querySelector(".time b"),
inputField = document.querySelector("input"),
refreshBtn = document.querySelector(".refresh-word"),
checkBtn = document.querySelector(".check-word");
let correctWord, timer;
const initTimer = maxTime => {
clearInterval(timer);
timer = setInterval(() => {
if(maxTime > 0) {
maxTime--;
return timeText.innerText = maxTime;
}
alert(`Time off! ${correctWord.toUpperCase()} was the correct word`);
initGame();
}, 1000);
}
const initGame = () => {
initTimer(20);
let randomObj = words[Math.floor(Math.random() * words.length)];
let wordArray = randomObj.word.split("");
for (let i = wordArray.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[wordArray[i], wordArray[j]] = [wordArray[j], wordArray[i]];
}
wordText.innerText = wordArray.join("");
hintText.innerText = randomObj.hint;
correctWord = randomObj.word.toLowerCase();;
inputField.value = "";
inputField.setAttribute("maxlength", correctWord.length);
}
initGame();
const checkWord = () => {
let userWord = inputField.value.toLowerCase();
if(!userWord) return alert("Please enter the word to check!");
if(userWord !== correctWord) return alert(`Oops! ${userWord} is not a correct word`);
alert(`Congrats! ${correctWord.toUpperCase()} is the correct word`);
initGame();
}
refreshBtn.addEventListener("click", initGame);
checkBtn.addEventListener("click", checkWord);
<div class="Gamecontainer">
<h2>Word Scramble</h2>
<div class="content">
<p class="word"></p>
<div class="details">
<p class="hint">Hint: <span></span></p>
<p class="time">Time Left: <span><b>20</b>s</span></p>
</div>
<input spellcheck="false" type="text" />
<div class="buttons">
<button class="refresh-word">Refresh Word</button>
<button class="check-word">Check Word</button>
</div>
</div>
</div>
Any suggestions?
This is because you use querySelector("input") which selects first found input element on the page. Blogger post has multiple input elements therefore your code selects a wrong element. Use IDs or classes to better identify your html elements.
For example you can narrow the query to your html part by using:
inputField = document.querySelector(".Gamecontainer input")
So I have a series of various JSON objects representing a college class with nested data inside each of them. Each of these objects are stored in an array called classes. Here is an example of how one of the class objects is formatted:
let class_A = {
professor: "Joey Smith",
numberStudents: 25,
courseCode: "COMS 2360",
seating: {
"FirstRow": {
0: {
firstName: "Sarah",
collegeMajor: "English",
},
1: {
firstName: "Bob",
collegeMajor: "Computer Engineering",
},
2: {
firstName: "Dylan",
collegeMajor: "Mathematics",
}
},
"SecondRow": {
3: {
firstName: "Molly",
collegeMajor: "Music"
}
}
}
};
Basically, I have a page with all students across all class objects laid out on a page with an add button next to each name, and the add button will eventually allow me to add students to certain groups for assignments, etc.
The page right now with only class_A would looks something like this:
I displayed the student names and the add button next to each student using code like this:
function loadStudents(){
let page = document.getElementById('page');
page.innerHTML = "";
for(seatRow in class.seating){
for(index in class.seating[seatRow]){
let studentName = class.seating[seatRow][index].studentName;
page.innerHTML += "<p> Name:" + studentName + " <img src='addButImg.png' id = 'addButton' onclick = 'addStudentToGroup()'></p>";
let addButton = document.getElementById("addButton");
addButton.alt = studentName;
console.log(addButton.alt);
}
}
}
function addStudentToGroup(){
let addButton = document.getElementById("addButton");
console.log(addButton.alt);
}
My page displays correctly like the picture, but I'm having trouble printing the name of the specific student I add to a group when I click on the add button next to the student's name. I assign the add button's alt value to the student's name, and tested it by doing "console.log(addButton.alt)" which prints:
Sarah
Bob
Dylan
Molly
If I click on the first add button, it should trigger the addStudentToGroup() function and print "Sarah" to the console. However, clicking on all the buttons seems to only print the last name in the list of students which is "Molly" regardless of whichever student the button is located next to. The alt seems to get saved as whatever the last student is, and I'm struggling to change the alt value based on whatever student's name I choose to click add for. Does anyone know how to fix this? Any help would be appreciated!
You are assigning the same id addButton to all images.
If you just want studentName then just pass it in onclick function.
like using template literal addStudentToGroup('${studentName}')
let class_A = {professor:"Joey Smith",numberStudents:25,courseCode:"COMS 2360",seating:{"FirstRow":{0:{firstName:"Sarah",collegeMajor:"English",},1:{firstName:"Bob",collegeMajor:"Computer Engineering",},2:{firstName:"Dylan",collegeMajor:"Mathematics",}},"SecondRow":{3:{firstName:"Molly",collegeMajor:"Music"}}}};
loadStudents();
function loadStudents(){
let page = document.getElementById('page');
page.innerHTML = "";
for(seatRow in class_A.seating){
for(index in class_A.seating[seatRow]){
//console.log(class_A.seating[seatRow][index]);
let studentName = class_A.seating[seatRow][index].firstName;
page.innerHTML += `<p> Name: ${studentName} <img src="addButImg.png" onclick = "addStudentToGroup('${studentName}')"></p>`;
//let addButton = document.getElementById("addButton");
//addButton.alt = studentName;
// console.log(addButton.alt);
}
}
}
function addStudentToGroup(sname){
console.log(sname);
}
<div id="page">
</div>
The problem is that all of the buttons have the same id "addButton", so when you try to get the button in addStudentToGroup it retrieves the last item with matching id.
Try sending a reference to the button as argument to addStudentToGroup:
onclick = 'addStudentToGroup(this)'
Try the following:
let classes = [class_A, class_B, class_C, class_D];
let classesAvailable = document.getElementById('classes');
let class = classes[classesAvailable.value];
function loadStudents(){
let page = document.getElementById('page');
page.innerHTML = "";
for(seatRow in class.seating){
for(index in class.seating[seatRow]){
let studentName = class.seating[seatRow][index].studentName;
page.innerHTML += "<p> Name:" + studentName + " <img src='addButImg.png' id = 'addButton' onclick = 'addStudentToGroup(this)'></p>";
let addButton = document.getElementById("addButton");
addButton.alt = studentName;
console.log(addButton.alt);
}
}
}
function addStudentToGroup(buttonEl){
console.log(buttonEl.alt);
}
I am trying to target the last word within a class and then wrap it with a span so that I can style the last word using Javascript.
<h1 class="title>A long tile</h1>
<h2 class="title>A long tile</h2>
becomes
<h1 class="title>A long <span class="last-word">tile</span></h1>
<h2 class="title>A long <span class="last-word">tile</span></h2>
I've seen some jQuery solutions on Stack which helped a bit, but I'd like a JS version.
I can get this working for the first element on the page, using this codeā¦
var paras = document.querySelector('.title');
function wrapLastWord(elem) {
const textContent = elem.textContent.split(" ");
const lastWord = textContent.pop();
// if the sentence is more than 1 word, wrap the last word with a span. If it's only 1 word, return it without being wrapped by a span
const updatedContent = textContent.join(" ") + (textContent.length > 0 ? ` <span class='last-word'>${lastWord}</span>` : lastWord);
elem.innerHTML = updatedContent;
}
wrapLastWord(paras)
However, I want to target all classes of .title and hence I thought I could use a querySelectorAll and a forEach. I am clearly not understanding how this works.
var paras = document.querySelectorAll('.title');
paras.forEach(function wrapLastWord(elem) {
const textContent = elem.textContent.split(" ");
const lastWord = textContent.pop();
// if the sentence is more than 1 word, wrap the last word with a span. If it's only 1 word, return it without being wrapped by a span
const updatedContent = textContent.join(" ") + (textContent.length > 0 ? ` <span class='last-word'>${lastWord}</span>` : lastWord);
elem.innerHTML = updatedContent;
}
wrapLastWord(paras)
})
Could anyone please give me some pointers to get this working, or suggest an alternative direction
To begin you have a syntax error in your second line missing an "
<h1 class="title>A long <span class="last-word">tile</span></h1>
<h2 class="title>A long <span class="last-word">tile</span></h2>
should be this
<h1 class="title">A long <span class="last-word">tile</span></h1>
<h2 class="title">A long <span class="last-word">tile</span></h2>
As for getting the value using javascript you can simply do
const spanText = document.querySelector('.last-word).innerText
// this will find the first match
console.log(spanText)
//if you want to find all of the ".last-words"
const lastWords = document.querySelectorAll('.last-word')
console.log(lastWords, "<-array like object")
lastWords.forEach((word)=> {
console.log(word.innerText)
})
As for your function
var paras = document.querySelectorAll(".title");
console.log(paras);
paras.forEach(function wrapLastWord(elem) {
const textContent = elem.innerText.split(" ");
console.log(textContent, ' textContent')
const lastWord = textContent.pop();
console.log(lastWord, 'last word')
// // if the sentence is more than 1 word, wrap the last word with a span. If it's only 1 word, return it without being wrapped by a span
const updatedContent = ` <span class='last-word'>${lastWord}</span>`;
console.log(updatedContent, 'updatedContent')
})
You've created updatedContent as you can see in your log, but now you have to decide what you want to do with it. Maybe use one of the append methods you can look at the docs and explore the append method if you want to add it to your page
#JimithyPicker Thanks, you led me to an answer.
My final code is as follows:
const paras = document.querySelectorAll(".title");
paras.forEach(function wrapLastWord(elem) {
const textContent = elem.textContent.split(" ");
const lastWord = textContent.pop();
// if the sentence is more than 1 word, wrap the last word with a span. If it's only 1 word, return it without being wrapped by a span
const updatedContent = textContent.join(" ") + (textContent.length > 0 ? ` <span class='last-word'>${lastWord}</span>` : lastWord);
elem.innerHTML = updatedContent;
});
I want to write a basic story where you just click next and the text changes.
I can change the text, but I don't know how to hide the button. Basically I want the onclick method to execute multiple functions, but not all at the same time, rather in a sequence
Code as below.
<!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>
<div id="div1">
<p id="txt" class="txt1">OK, here wo go.</p>
</div>
<button id="btn_next" type="button">Next</button>
<script>
document.getElementById("btn_next").addEventListener("click", toggleText);
function toggleText() {
var textBox = document.getElementById("txt");
switch (textBox.className) {
case "txt1": {
textBox.innerHTML = "This is text 1";
swapClasses(textBox, "txt2");
break;
}
case "txt2": {
textBox.innerHTML = "This is text 2";
break;
}
}
}
function swapClasses(elem, targetClass) {
elem.className = targetClass;
}
</script>
</body>
</html>
If you want to hide the button when the <p> class is txt2, which means the last text is shown, a simple way to do it would be this:
case "txt2": {
textBox.innerHTML = "This is text 2"
document.getElementById("btn_next").style.display = "none";
break;
}
You could also store the button element to a variable const btnEl = document.getElementById("btn_next") so you don't get it twice.
You can hide an element by setting its display to none like:
`nextBtn.style.display = 'none';
However, instead of using a switch statement, you can use an array of text values to drive your story as in the next answer
Another approach to this is shown below.
let counter = 0;
const displayed_text = [
'Input text 1',
'Input text 2',
'Input text 3',
'Input text 4',
];
// Assign DOM elements to variables
const btn_next = document.getElementById("btn_next");
const text_display = document.getElementById("txt");
// Attach listener to button
btn_next.addEventListener("click", toggleText);
function toggleText() {
counter += 1;
if (counter <= displayed_text.length) {
// Update displayed text
text_display.innerHTML = displayed_text[counter -1];
}
if (counter === displayed_text.length) {
// Hide button
btn_next.style.display = 'none';
}
}
The main advantage of this approach is that it makes it easier to go back multiple steps if you want.
var story = [
'OK, here wo go.',
'This is text 1',
'This is text 2',
'This is text 3',
'This is text 4'
];
var nextBtn = document.getElementById("btn_next");
function changeText() {
var textBox = document.getElementById("txt");
var chapter = Number(textBox.dataset.chapter);
if (chapter < story.length - 1) {
textBox.dataset.chapter = chapter + 1;
textBox.innerHTML = story[chapter + 1];
if ((story.length - chapter) <= 2 ) {
nextBtn.style.display = 'none';
}
}
}
nextBtn.addEventListener("click", changeText);
<div id="div1">
<p id="txt" class="txt1" data-chapter="0">OK, here wo go.</p>
</div>
<button id="btn_next" type="button">Next</button>
For cases like this, it can be beneficial to store the content in an array of objects (or fetch the content as JSON etc). Then, when the event handler is fired, it can simply increment (or decrement if you wish to have forward/backward) and determine whether the button should be visible or hidden. That appears to be the direction you're heading with the above code.
Example function:
function navigatePage(el){
// Control the navigation by only allowing increment within range
if (el != null){
switch (el.target.getAttribute("id")){
case "btn_next":
if (curr_page < story.length){
curr_page++;
}
break;
case "btn_prev":
if (curr_page > 1){
curr_page--;
}
break;
default: break;
}
}
// Set the title and text to the current page contents
// Arrays are zero-indexed, so "1" is actually "0", and so on
story_title.innerHTML = story[curr_page - 1].title;
story_content.innerHTML = story[curr_page - 1].text;
// Show or hide nav buttons based on the current page
// The following syntax is basically just a fancy "if-then" done in one line
btn_prev.style.display = (curr_page > 1 ? "inline-block" : "none");
btn_next.style.display = (curr_page < story.length ? "inline-block" : "none");
// Update the page count element
page_count.innerHTML = "Page " + curr_page + " of " + story.length;
// document.getElementById("storycontent").innerHTML = curr_page + " - " + story.length;
}
Here is a working fiddle to demonstrate how it all works together:
https://jsfiddle.net/s0toz3L8/1/
Call to the count function made by two group of checkboxes. First group represents categories, when clicked subjects for that category will be listed out.
html: id: counter displays count value. id: select replaces text acordingly
<div class="small-8 text-left columns" style="left:-30px;">
<span id="counter"><span id="count">0</span></span>
<span id="select">Select Subjects</span>
</div>
script:(categories group) To pass value for the subjects to be fetched by ajax. updateCount();is the count function call.
$("input[type=checkbox][id^=level]").change(function() {
var selectedval = $(this).val();
if($(this).is(":checked")) {
var selectedtext = $(this).next().text();
sendtobox(selectedval, $("#slider1").val(),"regis");
} else {
$("th."+selectedval).remove();
updateCount();
}
});
(subjects group)
$(document).on('change', '[id^=sub][type=checkbox]', updateCount);
count function:
function updateCount () {
$('#count').text($('[id^=sub][type=checkbox]:checked').length);
}
script to replace text:
$(".close-reveal-modal").on("click",function()
{
document.getElementById("select").innerHTML = "Select subject";
var str = document.getElementById("select").innerHTML;
var res = str.replace("Select subject", "Selected Subject");
document.getElementById("select").innerHTML = res;
});
Now I can replace text and the count works just fine! My problem is it doesn't obey the English grammar!
If 0 item/subjects returned, the text should be 0 Selected Subjects and if more than 1 is checked, it should say the same. See the (s) must be added in 'subject' word.
My problem is , I couldn't identify number of counts to replace this text.
I want someting like this:
if ($("#count") >1 || ($("#count")==0))
{
var res = str.replace("Select subject", "**Selected Subjects"**);
document.getElementById("select").innerHTML = res;
}
else
{
var res = str.replace("Select subject", "**Selected Subject"**);
document.getElementById("select").innerHTML = res;
}
I tried to alert $('#count').length , it red like this each time the checkbox checked:
1 1 1 1
What I'm expecting is
1 -when clicked once
2 - when clicked twice
This way would be easier for me to replace text indeed!
it sounds like you want the TEXT of the span with id 'count' for that comparison:
if ($("#count").text() == "1") {
// singular
}
else {
// plural
}