Hello everyone I can't do an exercise in html and javascript. How can I read from an input search multiple inputs and print them dynamically? for example if I write as input in the search bar "mark" I want to print "mark". If I then write "helen" in the search bar, I want to print: "mark", "helen", if I then write "gessy", I want to print "mark", "helen", "gessy" and so on.
page.html
<div class="container-fluid" >
<form class="d-flex" role="search">
<input class="form-control me-2" id="form-control me-2" type="search" placeholder="Search" aria-label="Search"> //here I write the inputs
<button class="btn btn-outline-success" type="button" onclick="send_tocontainer()">Search</button> //when i click the button i see all input value write from users
</form></div>
<div id="container-dx" >
<p id="text"></p>
</div>
script.js
function send_tocontainer(){
let element=document.getElementById("form-control me-2").value;
let newnode= document.createElement("p");
const textnode= newnode.createTextNode(element)
newnode.appendChild(textnode);
document.getElementById("testo").innerHTML=element
}
You could use an array to save the entries coming from your input. Then display them on the page by looping over that array and creating a tag to hold each entry and append it to your pages <p> element.
The benefit of saving the data to an array/object means you could also reference that data later.
See the snippit for an example.
const btn = document.querySelector('.btn')
const search = document.querySelector('form .me-2')
const textEl = document.getElementById('text')
const searchValues = []
const searchResults = (e) => {
// push the values into an array
searchValues.push(search.value)
// iterate over the array
searchValues.forEach((val, i) => {
// create a span tag to hold the display text from the array
let span = document.createElement('span')
// style the span so it is block element
span.style.display = 'block'
// is this the last iteration through, which would be the last entry into the form by user
// yes, then set the last value in the array to the textContent of our newly created span tag
i === searchValues.length - 1 ? span.textContent = searchValues[searchValues.length-1] : null
// append the text element
textEl.appendChild(span)
})
}
// event listener for button
btn.addEventListener('click', searchResults)
<div class="container-fluid">
<form class="d-flex" role="search">
<input class="form-control me-2" id="form-control me-2" type="search" placeholder="Search" aria-label="Search"> //here I write the inputs
<button class="btn btn-outline-success" type="button">Search</button> //when i click the button i see all input value write from users
</form>
</div>
<div id="container-dx">
<p id="text"></p>
</div>
Or you could just display the entries directly on the page without saving the input to some kind of array/object/etc...
See the snippit for an example.
const btn = document.querySelector('.btn')
const search = document.querySelector('form .me-2')
const textEl = document.getElementById('text')
const searchResults = (e) => {
let span = document.createElement('span')
span.style.display = 'block'
span.textContent = search.value
textEl.appendChild(span)
}
btn.addEventListener('click', searchResults)
<div class="container-fluid">
<form class="d-flex" role="search">
<input class="form-control me-2" id="form-control me-2" type="search" placeholder="Search" aria-label="Search"> //here I write the inputs
<button class="btn btn-outline-success" type="button">Search</button> //when i click the button i see all input value write from users
</form>
</div>
<div id="container-dx">
<p id="text"></p>
</div>
There are multiple ways you can complete this exercise. I've decided to use the local storage. It's important save the previous search state as it is required to be used on the next function call.
Rather than using element variable I'm using oldElement and newElement hoping they may self explain.
send_tocontainer = () => {
let newElement = document.getElementById("form-control me-2").value;
if (!localStorage.getItem('data')) {
localStorage.setItem('data', '[]');
}
let oldElement = JSON.parse(localStorage.getItem('data'));
oldElement.push(newElement);
localStorage.setItem('data', JSON.stringify(oldElement));
let serchContent = document.createElement("p");
serchContent.innerText = oldElement.toString();
document.body.appendChild(serchContent);
// let newnode = document.createElement("p");
// const textnode = newnode.createTextNode(element);
// newnode.appendChild(textnode);
// document.getElementById("testo").innerHTML = element
}
notice I have commented out the createTextNode as the function aren't defined in the question.
Here in local storage an array is created as data and new values are stored in to it. I also took liberty of creating a paragraph element to display your search results.
I've hosted this code here try to play around with it
https://stackblitz.com/edit/js-eamamp?file=index.html,index.js
Related
I have been trying for days now to figure out what I am doing wrong here. I have buttons for items that are located on different pages and they all use the same modal that contains a form and item details, depending on which button is selected.
The buttons have the same class and when clicked I need to get the attributes from the button's parent div (several divs above the button) and display the data from parent div in the modal. I am using Wordpress and I cannot add the attributes to the buttons, so I had to add them to a parent div.
I can get the code to work perfectly in visual studio but when I add it to Wordpress I keep getting errors in the console stating "Can't create duplicate variable that shadows a global property: 'l'" and "Can't create duplicate variable: 'modalBtns'". I cannot use button onclick for the buttons as Wordpress restricts that from what I have read, so I have to do it another way.
I have scoured Google and tried every suggestion I have found on this site and many others. I renamed 'modalBtns', broke code down into functions and put the functions outside the loop, added the functions inside the loop, changed modalBtns to var, constant..nothing is working. I don't know how to clear the errors.
I am also having issue with the modal not getting the data as the code has already ran prior to the modal loading so the id's for the modal divs I am putting the data in are not even present when code runs. I have to add item name to a hidden field of the form and add image, price, description. I tried delaying the code in the section where it is looking for modal divs but it still doesn't work.
This is what I have that works in Visual Studio but not on Wordpress. I don't know what I am doing wrong.
<div class="modalBtn" data-pkg="Package #1" data-price="124" data-duration="month" data-desc="This + that" data-img="main">
<div id="otherDiv">
<button id="Package1" class="premium-price-pricing-button">Package 1</button>
</div>
</div>
<div class="modalBtn" data-pkg="Package #2" data-price="234" data-duration="month" data-desc="Another descrpition" data-img="thumbnail">
<div id="otherDiv">
<button id="Package2" class="premium-price-pricing-button">Package 2</button>
</div>
</div>
<div class="modalBtn" data-pkg="Package #3" data-price="345" data-duration="each" data-desc="" data-img="custom">
<div id="otherDiv"></div>
<button id="Package3" class="premium-price-pricing-button" >Package 3</button>
</div>
<div id="modal">
<h1 id="modalTitle">This is the title</h1>
<img id="modalImg" src="defaultImg.png"/>
<p><span id="modalPrice">100</span><span id="modalDuration">month</span><span id="modalDesc">Description here</span></p>
<form action="/action_page.php">
<label for="name">First name:</label><br>
<input type="text" id="name" name="name" value="John"><br>
<label for="pkg">Package:</label><br>
<input type="text" id="pkg" class="pkgFormField" name="pkg" value="Doe"><br><br>
<input type="submit" value="Submit">
</form>
</div>
This is the code
//Get all buttons with classname premium-price-pricing-button
let modalBtns = document.getElementsByClassName('premium-price-pricing-button');
//Iterate through buttons & add event listener, when clicked run updateModal function
for (var i = 0; i < modalBtns.length; i++) {
modalBtns[i].addEventListener('click', updateModal);
}
function updateModal() {
//Get parent div which has data attributes
let parentDiv = this.closest('.modalBtn');
//Get/set attribute data-pkg from parent and set as pkg
let pkg = parentDiv.getAttribute("data-pkg");
//Get/set variables from parent attributes
let price= parentDiv.getAttribute("data-price");
let duration = parentDiv.getAttribute("data-duration");
let desc = parentDiv.getAttribute("data-desc");
let btnImg = parentDiv.getAttribute("data-img");
let modalImg = document.getElementById("modalImg");
//Find hidden form field & name field
let pkgField = document.getElementById("pkg");
let nameField = document.getElementById("name");
//Set default image for modal
let img = "image1.png";
//Find modal ids and replace innerHTML with parent attributes
document.getElementById("modalTitle").innerHTML = pkg;
document.getElementById("modalPrice").innerHTML = price;
document.getElementById("modalDuration").innerHTML = duration;
document.getElementById("modalDesc").innerHTML = desc;
//If img attribute is 'custom' or 'thumbnail' replace it with alternate image
if (btnImg == "custom"){
img = "image2.png";
}
if (btnImg == "thumbnail") {
img = "image3.png";
}
//Set img for modal
modalImg.src = img;
//Set pkg value in form to pkg
pkgField.value = pkg;
}
Wrap your JS Code within function like this:
(function () {
/**
* Put your code here.
*/
})();
HTML code
I want to display object values in this form in <p or easier solutions
<div class="control-form-id">
<label for="id">Id:</label>
<input type="text" name="id" id="id" required>
<button type="button" onclick="JSinHTML();" id="search" >Search</button>
</div>
<div class="serial">
<label for="serial">Serial number:</label>
<p id="serial">result</p>
</div>
<script>
function JSinHTML(){
let id_form ={}
id_form.input = document.getElementById("id").value
alert(id_form.input);
google.script.run.main(id_form);
document.getElementById("id").value = "";
}
</script>
GOOGLE SCRIPT code
function findId returns row number by typed id
function main(JSinHtml){
let numberRow = findId(JSinHtml.input);
Logger.log("input in main " + JSinHtml.input);
let toHtml = {};
toHtml.id = sheet_spis.getRange(numberRow, column_id).getValue();
toHtml.serial_number = sheet_spis.getRange(numberRow, column_serialnr).getValue();
toHtml.size = sheet_spis.getRange(numberRow, column_size).getValue();
toHtml.type = sheet_spis.getRange(numberRow, column_type).getValue();
Logger.log(toHtml); //I want to display separately this values in few <p>
}
In your situation, how about the following modification?
HTML & Javascript side:
From
google.script.run.main(id_form);
To:
google.script.run.withSuccessHandler(e => {
document.getElementById("serial").innerHTML = e.serial_number;
}).main(id_form);
Google Apps Script side:
From
Logger.log(toHtml); //I want to display separately this values in few <p>
To:
Logger.log(toHtml);
return toHtml;
Note:
From <p id="serial">result</p>, I guessed that you might have wanted to put the value of serial_number. So, I proposed it. If you want to show the whole object of toHtml, please modify document.getElementById("serial").innerHTML = e.serial_number; to document.getElementById("serial").innerHTML = JSON.stringify(e);.
Reference:
withSuccessHandler(function)
So I have this html form:
<form action="">
<input type="text" name="form-0-product_name" id="id-form-0-product_name">
<input type="text" name="form-0-product_price" id="id-form-0-product_price">
<button>Change form</button>
</form>
Please note the name and id attributes and how they contain "form-0". For a reason that doesn't really matter too much, I want the user to be able to click the "Change form" button and have all the instances of "form-0" change to "form-1". I came up with this javascript function that does that:
let button = document.querySelector("button");
let form = document.querySelector("form");
button.addEventListener("click", e => {
e.preventDefault();
const replacedForm = "form-0";
form.innerHTML = form.innerHTML.replaceAll(replacedForm, "form-1");
})
This does the trick of replacing the "form-0" strings with "form-1" ; however, it seems as though this completely resets the form. In other words, if the client has already typed some data into the text fields and then presses the change form button, the fields are cleared of their values. What I want to know is if there's a really efficient way to change the form's fields' attributes (mainly id and name) without clearing the values of the fields if their are values in them. Thanks and please let me know if I need to clarify.
You'll have to iterate over the elements and attributes individually.
let button = document.querySelector("button");
let form = document.querySelector("form");
button.addEventListener("click", e => {
e.preventDefault();
const replacedForm = "form-0";
// Select all elements with a name or id
for (const elm of form.querySelectorAll('[name], [id]')) {
for (const attrib of ['name', 'id']) {
elm[attrib] = elm[attrib].replaceAll(replacedForm, "form-1");
}
}
})
<form action="">
<input type="text" name="form-0-product_name" id="id-form-0-product_name">
<input type="text" name="form-0-product_price" id="id-form-0-product_price">
<button>Change form</button>
</form>
But this is a really strange thing to want to do in most cases. IDs in particular should not be dynamic. Strongly consider if there's an alternative way to approach the problem you're trying to solve.
You can also iterate over form.elements and modify the attribute's value property
const form = document.querySelector('form');
Array.from(form.elements).forEach(el => {
Array.from(el.attributes).forEach(att => {
att.value = att.value.replaceAll('form-0', 'form-1')
console.log(att.value)
});
})
<form action="">
<input type="text" name="form-0-product_name" id="id-form-0-product_name">
<input type="text" name="form-0-product_price" id="id-form-0-product_price">
<button>Change form</button>
</form>
I am trying to create a button that creates an input field every time I click on it. Currently when I click it it creates only only one input field, how can I make so that every time I click it I get an input field?
Here is my html:
<div id="new-input-container"> </div>
<p class="add-new-shareholders-p"><i class="fa fa-plus-circle fa-lg" #click="createNewInputFields"/>
and my function:
createNewInputFields() {
var container = document.getElementById('new-input-container')
container.innerHTML = "<input type='text'/>";
}
Using document.createElement, you can create new input HTMLElement and using container.appendChild function, you can add that new element to the div selector as follows.
function createNewInputFields() {
var container = document.getElementById('new-input-container');
const newElem = document.createElement("input");
newElem.setAttribute("type", "text");
container.appendChild(newElem);
}
<div id="new-input-container"> </div>
<button onclick="createNewInputFields()">Add New</button>
Depending on your logic, you can try one of these solutions :
First logic : Create inputs by a number
<template>
<div id="app">
<input type="text" v-for="i in numberOfInputs" :key="i" />
<br />
<button #click="addInput">Add input</button>
</div>
</template>
<script>
export default {
name: "App",
data: () => ({
numberOfInputs: 0,
}),
methods: {
addInput: function () {
this.numberOfInputs++;
},
},
};
</script>
Second logic: Create inputs by values
<template>
<div id="app">
<input
type="text"
v-for="(value, i) in values"
:key="i"
v-model="values[i]"
/>
<br />
<button #click="addInput">Add input</button>
</div>
</template>
<script>
export default {
name: "App",
data: () => ({
values: [],
}),
methods: {
addInput: function () {
let value = "";
this.values.push(value);
},
},
};
</script>
Your function will work fine, the only change that you need to make is, instead of setting value using innerHTML property, you can use the insertAdjacentHTML( ) function.
The reason your code only adds the input field once is because what innerHTML is doing here is just overwrite existing HTML each time you set a value using the assignment operator (=). That is because, innerHTML property just gets the innerHTML from the element like it is a string. One option is to concatinate the new input html to the existing innerHTML, the other is to use insertAdjacentHTML( ) function.
insertAdjacentHTML( ) will add adjacent html each time, takes in 2 parameters, first one is the place you want to insert which can be which can be one of ('beforebegin' 'beforeend' 'afterbegin' 'afterend'), in your case the best would be 'beforeend'. The second parameter is the HTML you want to add.
document.querySelector('.btn').addEventListener('click', createNewInputFields);
function createNewInputFields() {
const container = document.getElementById('new-input-container');
const inputHtml = "<input type='text'/>";
container.insertAdjacentHTML('beforeend', inputHtml);
}
<div id="new-input-container"></div>
<p class="add-new-shareholders-p">
<button class='btn'> create field</button>
</p>
I just fixed the bugs in your code.
To add a new item, you must use +=.
If you use only = the first time you will add an item.
But with each subsequent click, the item will be rewritten
The problem with this option is that when you add new fields, the content of the already created ones will be removed!
function createNewInputFields() {
var container = document.getElementById('new-input-container')
container.innerHTML += "<input type='text'/>";
}
<div id="new-input-container"> </div>
<p class="add-new-shareholders-p"><i class="fa fa-plus-circle fa-lg" onclick="createNewInputFields()">Click Me</i></p>
The correct way to add a new field while keeping the idea of your code and saving information in already created fields is:
function createNewInputFields() {
var container = document.getElementById('new-input-container');
var x = document.createElement("input");
x.setAttribute('type', 'text');
container.appendChild(x);
}
<div id="new-input-container"> </div>
<p class="add-new-shareholders-p"><i class="fa fa-plus-circle fa-lg" onclick="createNewInputFields()">Click Me</i></p>
EDIT: I changed the var to class but I might have some error in here.
Here it goes, I want to have this paragraph in which the user can change the name on the following paragraph. The code I'm using only changes one name but the rest remains the same.
<script type="text/javascript">
function changey(){
var userInput = document.getElementById('userInput').value;
var list = document.getElementByClassName('kiddo');
for (let item of list) {
item.innerHTML = userInput;
}
}
</script>
<input id="userInput" type="text" value="Name of kid" />
<input onclick="changey()" type="button" value="Change Name" /><br>
Welcome to the site <b class="kiddo">dude</b> This is how you create a document that changes the name of the <b class="kiddo">dude</b>. If you want to say <b class="kiddo">dude</b> more times, you can!
No error messages, the code only changes one name instead of all three.
Use class="kiddo" instead of id in the html.
You can then use var kiddos = document.getElementsByClassName('kiddo') which will return an array of all the elements of that class name stored in kiddos.
Then you just need to loop through the values and change what you want.
Example of loop below:
for (var i = 0; i < kiddos.length; i++) {
kiddos[i].innerHTML = userInput;
}
id should be unique on the page. Javascript assumes that there is only one element with any given id. Instead, you should use a class. Then you can use getElementsByClassName() which returns an entire array of elements that you can iterate over and change. See Select ALL getElementsByClassName on a page without specifying [0] etc for an example.
Hello You should not use id, instead use class.
Welcome to the site <b class="kiddo">dude</b> This is how you create a document that changes the name of the <b class="kiddo">dude</b>. If you want to say <b class="kiddo">dude</b> more times, you can!
After That on Js part :
<script type="text/javascript">
function changey(){
var userInput = document.getElementById('userInput').value;
var list = document.getElementByClassName('kiddo');
for (let item of list) {
item.innerHTML = userInput;
}
}
</script>
you should use class instated of id. if you use id then the id [kiddo] must be unique
In short, document.querySelectorAll('.kiddo') OR
document.getElementsByClassName('kiddo') will get you a list of elements to loop through. Take note of querySelectorAll, though - it uses a CSS selector (note the dot) and doesn't technically return an array (you can still loop through it, though).
See the code below for some full working examples (const and arrow functions are similar to var and function, so I'll put up a version using old JavaScript, too):
const formEl = document.querySelector('.js-name-change-form')
const getNameEls = () => document.querySelectorAll('.js-name')
const useNameFromForm = (formEl) => {
const formData = new FormData(formEl)
const nameValue = formData.get('name')
const nameEls = getNameEls()
// Set the text of each name element
// NOTE: use .textContent instead of .innerHTML - it doesn't get parsed, so it's faster and less work
nameEls.forEach(el => el.textContent = nameValue)
}
// Handle form submit
formEl.addEventListener('submit', (e) => {
useNameFromForm(e.target)
e.preventDefault() // Prevent the default HTTP request
})
// Run at the start, too
useNameFromForm(formEl)
.name {
font-weight: bold;
}
<!-- Using a <form> + <button> (submit) here instead -->
<form class="js-name-change-form">
<input name="name" value="dude" placeholder="Name of kid" />
<button>Change Name</button>
<form>
<!-- NOTE: Updated to use js- for js hooks -->
<!-- NOTE: Changed kiddo/js-name to spans + name class to remove design details from the HTML -->
<p>
Welcome to the site, <span class="js-name name"></span>! This is how you create a document that changes the name of the <span class="js-name name"></span>. If you want to say <span class="js-name name"></span> more times, you can!
</p>
var formEl = document.querySelector('.js-name-change-form');
var getNameEls = function getNameEls() {
return document.querySelectorAll('.js-name');
};
var useNameFromForm = function useNameFromForm(formEl) {
var formData = new FormData(formEl);
var nameValue = formData.get('name');
var nameEls = getNameEls(); // Set the text of each name element
// NOTE: use .textContent instead of .innerHTML - it doesn't get parsed, so it's faster and less work
nameEls.forEach(function (el) {
return el.textContent = nameValue;
});
};
// Handle form submit
formEl.addEventListener('submit', function (e) {
useNameFromForm(e.target);
e.preventDefault(); // Prevent the default HTTP request
});
// Run at the start, too
useNameFromForm(formEl);
<button class="js-get-quote-btn">Get Quote</button>
<div class="js-selected-quote"><!-- Initially Empty --></div>
<!-- Template to clone -->
<template class="js-quote-template">
<div class="js-quote-root quote">
<h2 class="js-quote"></h2>
<h3 class="js-author"></h3>
</div>
</template>
You have done almost everything right except you caught only first tag with class="kiddo".Looking at your question, as you need to update all the values inside tags which have class="kiddo" you need to catch all those tags which have class="kiddo" using document.getElementsByClassName("kiddo") and looping over the list while setting the innerHTML of each loop element to the userInput.
See this link for examples:https://www.w3schools.com/jsref/met_document_getelementsbyclassname.asp
try:
document.querySelectorAll('.kiddo')
with
<b class="kiddo">dude</b>