I have a script that randomly generates a room id when joined. I want to copy that ID with a click of a button. It would be easy job with a input element, however, I don't know how to even target that random ID to edit and manipulate it. How could I do that?
function createRoom(){
var option = document.createElement("option");
option.text = makeid(10);
roomSelection.add(option);
window.sessionStorage.setItem("arhostas", 1);
}
function makeid(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
var roomUrl = document.createElement("div");
roomUrl.innerText = `Room id: ${room}`
roomID.append(roomUrl)
<div id='roomId'></div>
Room ID is already generated when joined to the room. I just need to copy it to the clipboard somehow. Adding a "createRoom" code.
room_id_div is not a valid html-element. You can create an element and assign some properties to it in one go using Object.assign. If you want to use the id within the innerText of the created element, you'll have to create the (random) id separately.
Alternatively you can set the content of a div using a pseudo-selector in css (:before). In that case you don't need to create a random id separately. The downside is that the text within the div can not be selected (hence, not copied to the clipboard).
Both demonstrated in this snippet:
document.addEventListener("click", handle);
document.addEventListener("change", handle);
function handle(evt) {
const origin = evt.target;
if (/Room$/.test(origin.id)) {
return origin.id === "fromIdRoom" ?
createRoom1() : createRoom2();
} else if (origin.id === "roomSelector") {
if (origin.value !== "-1") {
document.querySelectorAll("#roomId1 div")
.forEach(elem => elem.style.backgroundColor = "");
document.querySelector(`#${origin.value}`).style.backgroundColor = "#FFFFC0";
}
}
}
// room id from css pseudo :before
// use [makeId] directly
function createRoom1() {
const roomParent = document.querySelector("#roomId1");
roomParent.append(
Object.assign(
document.createElement("div"), {
id: `X${makeId(15)}`, // NOTE: id can not start with a number
})
);
const idNow = roomParent.querySelector("div:last-child").id;
roomParent.querySelector("select").append(
Object.assign(
document.createElement("option"), {
value: idNow,
textContent: idNow
})
);
}
// room id within innerText
// you'll need to pre-assign [room]
function createRoom2() {
const room = `X${makeId(15)}`; // NOTE: id can not start with a number
document.querySelector("#roomId2").append(
Object.assign(
document.createElement("div"), {
id: room,
innerText: `Room id: ${room}`,
})
);
}
function makeId(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
#roomId1 div:before {
content: 'Room id from css: 'attr(id);
}
<p>
<button id="fromIdRoom">create create a room within #roomId1</button>
<button id="createRoom">create a room within #roomId2</button>
</p>
<div id='roomId1'>
<select id="roomSelector">
<option value="-1">Select room</option>
</select>
</div>
<div id='roomId2'></div>
The navigator.clipboard API is the modern method for copying to the clipboard navigator.clipboard. The tab must be active for you to copy to the clipboard for security reasons. So you can't copy the id in this snippet
You created an element room_id_div that isn't a valid HTML element. So I changed it to a normal div tag.
I created a button to listen for click and then copy the text.
const length = 7;
const button = document.getElementById('copyId');
const roomID = document.getElementById('roomId');
const roomUrl = document.createElement("div");
function makeId(length) {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
button.addEventListener('click', _ => {
roomID.innerHTML = '';
const id = makeId(length);
navigator.permissions.query({
name: "clipboard-write"
}).then(permission => {
if (permission.state == 'granted') navigator.clipboard.writeText(id).then(_ => alert('Successfully copied to clipboard!!'), _ => alert('Error copying id to clipboard'));
else alert('Error copying id to clipboard');
});
roomUrl.innerText = `Room id: ${id}`;
roomID.append(roomUrl);
});
<div id='roomId'></div>
<button id="copyId">Generate and Copy Id</button>
Related
As the title suggests I am trying to find the index of a placeholder text element in a google doc table so that I can replace it with text stored in a different doc.
I can get the pre-formatted text to be added to the document - not the place in the table required - using other examples I have found on stackoverflow.
However I am unclear as how to find the index of the placeholder element within one of many tables in the template document.
I need the index of the placeholder text to be able to use the insertParagraph function.
To add slightly more detail: I am able to find the placeholder text and insert an image using the below code.
function replaceTextToImage(body, searchText, image, width) {
var next = body.findText(searchText);
if (!next) return;
var r = next.getElement();
r.asText().setText("");
var img = r.getParent().asParagraph().insertInlineImage(0, image);
if (width && typeof width == "number") {
var w = img.getWidth();
var h = img.getHeight();
img.setWidth(width);
img.setHeight(width * h / w);
}
return next;
};
However, I need to preserve the formatting of the doc I want to import. So I open the document with the formatted text and then loop through the different element types with a conditional to insert the text/image if the element type is matched. This is why I need the index of the placeholder text. See for function below:
function replaceTextWithDoc(body, searchText, id) {
let doc = DocumentApp.openById(id)
var numElements = body.getNumChildren();
var index = numElements;
for (var i = 0; i < numElements; i++) {
var child = body.getChild(i);
if (child.asText().getText() == searchText){
index = i;
body.removeChild(child);
break;
}
}
var totalElements = doc.getNumChildren();
for( var j = 0; j < totalElements; ++j ) {
var element = doc.getChild(j).copy();
var type = element.getType();
if( type == DocumentApp.ElementType.PARAGRAPH )
body.insertParagraph(index, element);
else if( type == DocumentApp.ElementType.TABLE )
body.insertTable(index, element);
else if( type == DocumentApp.ElementType.LIST_ITEM )
body.insertParagraph(index, element);
else
throw new Error("According to the doc this type couldn't appear in the body: "+type);
}
}
Here is an example of the placeholder text ( {iText} ) in a table: https://docs.google.com/document/d/1mZWpQqk4gYAF6UCRALrT8S99-01RYNfwni_kqDzOg7E/edit?usp=sharing
Here is an example of text and images that I need to replace the placeholder text with - maintaining all/any formatting. https://docs.google.com/document/d/1wuX0g5W2GL0YJ7admiv3TNEepb_zVwQleKwazCiAMBU/edit?usp=sharing
Issue:
If I understand you correctly, you want to copy the contents of one document (made up of text and inline images) to certain table cells that contain a certain placeholder text.
Solution:
In that case, I'd suggest the following:
Iterate through all tables in the target document, using Body.getTables().
For each table, iterate through all its cells.
For each cell, check whether its text contains the placeholder.
If the placeholder is included, clear the current cell content via TableCell.clear().
Iterate through all source document elements (see for example, this answer).
For each element, check its type (Element.getType()).
If the element is a paragraph, append the paragraph to the cell via TableCell.appendParagraph.
If the element is an image, append it via TableCell.appendImage.
Code sample:
const PLACEHOLDER = "{iText}";
function myFunction() {
const doc = DocumentApp.openById(TARGET_ID);
const sourceDoc = DocumentApp.openById(SOURCE_ID);
const body = doc.getBody();
const tables = body.getTables();
tables.forEach(table => {
const numRows = table.getNumRows();
for (let i = 0; i < numRows; i++) {
const row = table.getRow(i);
const numCells = row.getNumCells();
for (let j = 0; j < numCells; j++) {
const cell = row.getCell(j);
const cellText = cell.editAsText();
const text = cellText.getText();
if (text.includes(PLACEHOLDER)) {
cell.clear();
appendSourceContent(sourceDoc, cell);
}
}
}
});
}
function appendSourceContent(doc, cell) {
const numChildren = doc.getNumChildren();
for (let j = 0; j < numChildren; j++) {
const element = doc.getChild(j).copy();
const type = element.getType();
if (type == DocumentApp.ElementType.PARAGRAPH) {
cell.appendParagraph(element);
} else if (type == DocumentApp.ElementType.INLINE_IMAGE) {
cell.appendImage(element);
}
}
}
Note:
Add additional else if blocks if the source content can have different ElementTypes than paragraphs and inline images.
I assumed that you want to preserve none of the current content in the table cell.
I have a problem with the function below. It's taking the data from JSON and it's creating a menu item. The problem is when there are more than 2 menu items, and I try to increase the quantity of the first item then the value of the second item is increasing.
function ShowTheMenu(theCategoryId) {
var parentEl = document.getElementById("itemlist");
ClearMenu();
for (let i = 0; i < data.length; i++) {
if (data[i].KategorijaBroj == theCategoryId) {
// MAIN PARENT
var itemBox = document.createElement("div");
itemBox.classList.add("itembox");
var itemImage = document.createElement("img");
itemImage.classList.add("itemimage");
itemImage.src = "/menuitemsimages/" + data[i].Image;
var itemContent = document.createElement("div");
itemContent.classList.add("itemcontent");
var itemTitle = document.createElement("h3");
itemTitle.classList.add("itemtitle");
itemTitle.innerHTML = data[i].Title;
var itemPrice = document.createElement("p");
itemPrice.classList.add("itemprice");
itemPrice.innerHTML = "$" + data[i].Price;
var itemQnt = document.createElement("p");
itemQnt.classList.add("quantity");
itemQnt.innerHTML = "Quantity";
var buttonsBox = document.createElement("div");
buttonsBox.classList.add("divcontrolbtns");
var itemQuantity = 0;
var quantityValue = document.createElement("div");
quantityValue.innerHTML = itemQuantity;
var increaseBtn = document.createElement("div");
increaseBtn.classList.add("controlbtns");
increaseBtn.innerHTML = "+";
increaseBtn.addEventListener("click", function () {
if(itemQuantity < 10) {
itemQuantity++;
}
quantityValue.innerHTML = itemQuantity;
})
var decreaseBtn = document.createElement("div");
decreaseBtn.classList.add("controlbtns");
decreaseBtn.innerHTML = "-";
decreaseBtn.addEventListener("click", function () {
if(itemQuantity > 0) {
itemQuantity--;
}
quantityValue.innerHTML = itemQuantity;
})
var itemAddToCart = document.createElement("button");
itemAddToCart.classList.add("btn-add-to-cart");
itemAddToCart.textContent = "Add to cart";
var itemDesc = document.createElement("p");
itemDesc.classList.add("itemdesc");
itemDesc.innerHTML = data[i].Description;
itemBox.appendChild(itemImage);
itemContent.appendChild(itemTitle);
itemContent.appendChild(itemDesc);
itemContent.appendChild(itemPrice);
itemContent.appendChild(itemAddToCart);
itemContent.appendChild(itemQnt);
buttonsBox.appendChild(increaseBtn);
buttonsBox.appendChild(quantityValue);
buttonsBox.appendChild(decreaseBtn);
itemContent.appendChild(buttonsBox);
itemBox.appendChild(itemContent);
parentEl.appendChild(itemBox);
}
}
}
IMAGE
What should I do in order for the chosen menu item value to be changed?
Try to do something like this bellow. I try to use same HTML structure that you use but to be honest, I suggest that you change a little bit ;)
<!DOCTYPE html>
<html>
<head>
<script>
// Qt
var quantity = new Array();
function ShowTheMenu(theCategoryId) {
// Clear menu
// ClearMenu();
// bt+
increaseBtn = (i) => {
// Item target
let item = document.getElementById('item_' + i);
// Qt target
let qtSpan = item.getElementsByClassName('qt');
// Qt
let qt = parseInt(qtSpan[0].innerHTML);
// Fix some errors
if (qt === undefined || !qt) qt = 0;
// Increase
if (qt < 10) qt++;
// Update
qtSpan[0].innerHTML = qt;
};
// bt-
decreaseBtn = (i) => {
// Item target
let item = document.getElementById('item_' + i);
// Qt target
let qtSpan = item.getElementsByClassName('qt');
// Qt
let qt = parseInt(qtSpan[0].innerHTML);
// Fix some errors
if (qt === undefined || !qt) qt = 0;
// Decrease
if (qt > 0) qt--;
// Update
qtSpan[0].innerHTML = qt;
};
//
var data = new Array();
data[0] = {
Image:
'https://s2.glbimg.com/WcYUQNaattnUf7d8U8MUBfk7loU=/620x430/e.glbimg.com/og/ed/f/original/2015/10/30/pizza.jpg',
KategorijaBroj: 1,
Title: 'Delicious Pizza',
Price: 10,
Description: 'Description test',
};
for (let i = 0; i < data.length; i++) {
if (data[i].KategorijaBroj == theCategoryId) {
// Img
let img = data[i].Image; // '/menuitemsimages/' + data[i].Image;
// Title
let title = data[i].Title;
// Price
let price = '$' + data[i].Price;
// Description
let desc = data[i].Description;
// Qtd
let qt = 2;
// Matriz
let newItem = `<div id="item_${i}" class="itembox">
<div class="itemcontent">
<img src="${img}" border=0 width=100/>
<h3 class="itemtitle">${title}</h3>
<p class="itemprice">${price}</p>
<div class="quantity">
<span>Quantity : </span>
<span class="qt">${qt}</span>
</div>
<div class="controlbtns">
<button class="addbtn" onClick="increaseBtn(${i})">+</button>
<button class="removebtn" onClick="decreaseBtn(${i})">-</button>
</div>
<button class="btn-add-to-cart">Add to cart</button>
<p class="description">${desc}</p>
</div>
</div>`;
// Get the menulist itens
let parentEl = document.getElementById('itemlist');
// Add item
parentEl.insertAdjacentHTML('beforeend', newItem);
}
}
}
</script>
</head>
<body>
<div id="itemlist"></div>
<script>
ShowTheMenu(1);
</script>
</body>
</html>
It's because both items are sharing the same variable, in this case, itemQuantity.
Option 1
If they all should have their own counter I would recommend using an object for tracking this.
const itemQuantity = {
'item1': 2,
'item2': 5
}
if you add some unique class or id to the element you can use this in your onclick event to use as a key. (Where I used 'item1' and 'item2')
Option 2
If you create a function that does everything that's inside your for loop and then just call that function it should also work. This works because every function then creates its own scoped variable of itemQuanity.
Go with whatever options feel best for now. How to manage data in your frontend has a lot of different ways and opinions. You'll quickly discover what works best in what scenario.
What Olavo Mello is mentioning in his answer could still make your code better. using string literals for small HTML snippets is often more readable than using document.createElement(). I would recommend fixing your counter issue first and then look if you could improve your code with Olavo Mello's answer in mind. Good luck :)
I have a variable called 'newItem' which essentially is a block of html code that will be appended directly to the dom when activated (this code is for a javascript shopping cart). I have the line of 1 below and am trying to access the textContent of 'amount-items' on the very last div (class='dropDown-price') as indicated by Number(amountItems.textContent) but am left with a null on the console.
What am i doing wrong, why doesnt .textContent gain access to the '1' for the 'amount-items' class?
Thanks for any help i can get
//dropdown menu hidden
const cartDropdown = document.querySelector('.cart-dropDown-items');
//every single + symbol
const addToCartButtons = document.querySelectorAll('.addToCart');
//price of item
const foodPrices = document.querySelectorAll('.selection-row-title');
//name of item
const foodNames = document.querySelectorAll('.selection-row-foodName');
//weight of item
const foodWeights = document.querySelectorAll('.selection-row-weight');
const items = [];
let total = 0;
for (let i=0; i<addToCartButtons.length; i++) {
addToCartButtons[i].addEventListener('click', function() {
const newItem = document.createElement('div');
newItem.className = 'dropDown-item';
let amountItems = document.querySelector('.amount-items');
newItem.innerHTML =
`<div class='dropDown-title dropDown-info'>
${foodNames[i].innerHTML}
</div>
<div class='dropDown-amount dropDown-info'>
<p class='amount-items'>1</p>
</div>
<div class='dropDown-price dropDown-info'>
${Number(foodPrices[i].innerHTML.substring(1)) * Number(amountItems.textContent)}
</div>`;
console.log(newItem)
// if item currently exists in array, just update amount in checkout and increase count++
if (items.includes(addToCartButtons[i].value)) {
items.push(addToCartButtons[i].value);
for (let i=0; i<items.length; i++) {
if (items[i].includes(addToCartButtons[i].value)) {
Number(amountItems.innerHTML) + 1;
}
}
}
// if items does not exist in array, update dom with new item UI and count = 1 by default
else {
items.push(addToCartButtons[i].value);
cartDropdown.appendChild(newItem);
}
console.log(items)
})
}
My goal:
Let users highlight different substring in a single long string.
However, once I've highlighted one substring with range.surroundContents(newNode) (newNode is a span with yellow background), the innerHTML of the whole long string changed-- it started to contain the span element; consequently, if the user wants to highlight a substring after the previous highlighted substring in the same long string, the anchorOffset will return the index starting after the previous span.
For example, in this long string:
"Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much."
this long sentence is wrapped by a p whose class name is noting. If the range.surroundContents() method the substring "Privet Drive", then, when I want to get the window.getSelection().anchorOffset of the substring "thank", the answer wrongly is 53 while the correct answer should be 102.
How should I do? Thank you!!
P.S. I don't want to use substring method to find the position, thank you!
$(".noting").mouseup(function(e){
$("#noteContent").val("");/*flushing*/
curSentNum = $(this).attr("id").split("-")[1];
$('#curSentNum').val(curSentNum);
highlightLangName = $(this).attr("id").split("-")[2];
$('#highlightLangName').val(highlightLangName);
//console.log(".noting $(this).html()"+$(this).html()+" "+$(this).attr("id"));//id, for example: p-2-French
if (window.getSelection) {
highlightedText = window.getSelection().toString();
curAnchorOffset = window.getSelection().anchorOffset;
$('#anchorAt').val(curAnchorOffset);
$('#highlightLen').val(highlightedText.length);
}
else if (document.selection && document.selection.type != "Control") {
highlightedText = document.selection.createRange().text;
}
});
And then I'll save the anchorAt information to db; after the db operation, I'll immediately call this function using the previous variables remained:
function highlightNoteJustSaved(){
var curI = noteCounter;
var anchorAt = parseInt($("#anchorAt").val());
var highlightLen = parseInt($("#highlightLen").val());
/*p to find, for example: p-2-French*/
var curP = document.getElementById('p-'+curSentNum.toString()+"-"+$("#highlightLangName").val());
var range = document.createRange();
root_node = curP;
range.setStart(root_node.childNodes[0], anchorAt);
range.setEnd(root_node.childNodes[0], anchorAt+highlightLen);
var newNode = document.createElement("span");
newNode.style.cssText="background-color:#ceff99";//yellow
newNode.className = alreadyNoteStr;
newNode.setAttribute('id','already-note-'+curI.toString());
range.surroundContents(newNode);
}
for HTML tree node structure, please take a look at the comment below( I didn't figure out how to copy-paste the code at this asking area).
I replaced your method to highlight text with 2 methods. highlightTextNodes finds the word in the content of the node. Searching each child. Also I implemented a highlight remover to show how it works. I replaced the span with a mark tag.
let alreadyNoteStr = 'already';
let noteCounter = 0;
let elementId;
$('p.noting').mouseup(function(e) {
elementId = $(this).attr('id');
$('#noteContent').val(''); /*flushing*/
curSentNum = elementId.split('-')[1];
$('#curSentNum').val(curSentNum);
highlightLangName = elementId.split('-')[2];
$('#highlightLangName').val(highlightLangName);
//console.log(".noting $(this).html()"+$(this).html()+" "+$(this).attr("id"));//id, for example: p-2-French
if (window.getSelection) {
highlightedText = window.getSelection().toString();
curAnchorOffset = window.getSelection().anchorOffset;
$("#noteContent").val(highlightedText);
$('#anchorAt').val(curAnchorOffset);
$('#highlightLen').val(highlightedText.length);
highlight(elementId, highlightedText);
} else if (document.selection && document.selection.type != "Control") {
highlightedText = document.selection.createRange().text;
}
});
function highlightNoteJustSaved() {
let curI = noteCounter;
let anchorAt = parseInt($("#anchorAt").val());
let highlightLen = parseInt($("#highlightLen").val());
/*p to find, for example: p-2-French*/
let curP = document.getElementById('p-' + curSentNum.toString() + "-" + $("#highlightLangName").val());
let range = document.createRange();
rootNode = curP;
let childNode = rootNode.childNodes[0];
range.setStart(rootNode.childNodes[0], anchorAt);
range.setEnd(rootNode.childNodes[0], anchorAt + highlightLen);
var newNode = document.createElement("span");
newNode.style.cssText = "background-color:#ceff99"; //yellow
newNode.className = alreadyNoteStr;
newNode.setAttribute('id', 'already-note-' + curI.toString());
range.surroundContents(newNode);
}
/*
* Takes in an array of consecutive TextNodes and returns a document fragment with `word` highlighted
*/
function highlightTextNodes(nodes, word) {
if (!nodes.length) {
return;
}
let text = '';
// Concatenate the consecutive nodes to get the actual text
for (var i = 0; i < nodes.length; i++) {
text += nodes[i].textContent;
}
let fragment = document.createDocumentFragment();
while (true) {
// Tweak this if you want to change the highlighting behavior
var index = text.toLowerCase().indexOf(word.toLowerCase());
if (index === -1) {
break;
}
// Split the text into [before, match, after]
var before = text.slice(0, index);
var match = text.slice(index, index + word.length);
text = text.slice(index + word.length);
// Create the <mark>
let mark = document.createElement('mark');
mark.className = 'found';
mark.appendChild(document.createTextNode(match));
// Append it to the fragment
fragment.appendChild(document.createTextNode(before));
fragment.appendChild(mark);
}
// If we have leftover text, just append it to the end
if (text.length) {
fragment.appendChild(document.createTextNode(text));
}
// Replace the nodes with the fragment
nodes[0].parentNode.insertBefore(fragment, nodes[0]);
for (var i = 0; i < nodes.length; i++) {
let node = nodes[nodes.length - i - 1];
node.parentNode.removeChild(node);
}
}
/*
* Highlights all instances of `word` in `$node` and its children
*/
function highlight(id, word) {
let node = document.getElementById(id);
let children = node.childNodes;
let currentRun = [];
for (var i = 0; i < children.length; i++) {
let child = children[i];
if (child.nodeType === Node.TEXT_NODE) {
// Keep track of consecutive text nodes
currentRun.push(child);
} else {
// If we hit a regular element, highlight what we have and start over
highlightTextNodes(currentRun, word);
currentRun = [];
// Ignore text inside of our <mark>s
if (child.nodeType === Node.ELEMENT_NODE && child.className !== 'found') {
highlight(child, word);
}
}
}
// Just in case we have only text nodes as children
if (currentRun.length) {
highlightTextNodes(currentRun, word);
}
}
/*
* Removes all highlighted <mark>s from the given node
*/
function unhighlight(id) {
let node = document.getElementById(id);
let marks = [].slice.call(node.querySelectorAll('mark.found'));
for (var i = 0; i < marks.length; i++) {
let mark = marks[i];
// Replace each <mark> with just a text node of its contents
mark.parentNode.replaceChild(document.createTextNode(mark.childNodes[0].textContent), mark);
}
}
label {
display: block;
position: relative;
padding-left: 100px;
}
button {
margin-top: 20px;
margin-bottom: 20px;
padding: 10px;
}
label>span {
position: absolute;
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" onclick="unhighlight(elementId);">Unhighlight</button>
<div id="div-0" class="only-left-border">
<p class="lan-English noting" id="p-1-English">Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much.</p>
</div>
<label><span>Content:</span><input type="text" id="noteContent"></input></label>
<label><span>Numer:</span><input type="text" id="curSentNum"></input></label>
<label><span>Language:</span><input type="text" id="highlightLangName"></input></label>
<label><span>Anchor:</span><input type="text" id="anchorAt"></input></label>
<label><span>Length:</span><input type="text" id="highlightLen"></input></label>
What I am trying to accomplish is have the user click button one and a text field is created, this button is pushed 3 times and 3 text fields appear. When each text field appears it should the user should then enter text in each text field. Once all text fields are filled by the user, there is a second button that when clicked; should display and sort the manually entered input fields text in a bonafide node list by alphabetical order.
(NOT AN ARRAY) it must be a true nodelist. Keep in mind, each input field is being created upon the push of button #1. Then the user entered information is being displayed and sorted when pushing button #2. A for-loop should be used to retrieve value of each element of the nodelistand store each value into an element of the new listItemValues array.
Appreciate any help.
javascript:
var $ = function (id) {
return document.getElementById(id)
}
var adding = function() {
var newInput = document.createElement("input");
var newBreak = document.createElement("br");
var myparent = $("todolist");
newInput.setAttribute("title", "text");
newInput.setAttribute("class", "listitem");
myparent.appendChild(newInput);
myparent.appendChild(newBreak);
};
var sorting = function() {
var display = "";
var listItemValues = document.getElementsByTagName("input");
for (i = 1; i <= listItemValues.length; i++)
var myItem = $("additem") + i;
var myItemName = (myItem).value;
display += myItemName;
}
window.onload = function() {
$("additem").onclick = adding;
$("sortitems").onclick = sorting;
}
I have made some changes to your code to make it a completely a javascriptsolution.
To reduce the use of the repetitive syntax of document.getElementById and document.createElement. I have 2 Function Declarations:
function id(id) {
return document.getElementById(id);
}
function ce(el) {
return document.createElement(el);
}
Other change is in the Function Expression adding() where I've added: newInput.type = "text"; to setting the input type when you click in the Add Item button.
In the Function Expression sorting() I've declared:
nodeList = document.querySelectorAll("input[type=text]");
The document.querySelectorAll() method returns a list of the
elements within the document (using depth-first pre-order traversal of
the document's nodes) that match the specified group of selectors. The
object returned is a NodeList.
Finally I've made a Function Expression printSortedValues() to print the sorted values in <p id="displayitems"></p>. In this function use the Array.prototype.sort() to sort its values ascending.
var printSortedValues = function(listItemValues) {
listItemValues.sort(); // Sorting the values.
var html = "", i, len = listItemValues.length;
for (i = 0; i < len; i++) {
html += "<span>";
html += listItemValues[i];
html += "</span>";
}
return html; // Return the html content with the sorted values.
};
Something like this:
function id(id) {
return document.getElementById(id);
}
function ce(el) {
return document.createElement(el);
}
var adding = function() {
var newInput = ce("input"), newBreak = ce("br"), myparent = id("todolist");
newInput.setAttribute("title", "Some title...");
newInput.setAttribute("class", "listitem");
newInput.type = "text";
myparent.appendChild(newInput);
myparent.appendChild(newBreak);
};
var sorting = function() {
var listItemValues = [], nodeList = document.querySelectorAll("input[type=text]"), i, len = nodeList.length, node;
for (i = 0; i < len; i++) {
node = nodeList[i];
listItemValues.push(node.value); // Store its values.
}
id("displayitems").innerHTML = printSortedValues(listItemValues);
};
var printSortedValues = function(listItemValues) {
listItemValues.sort(); // Sorting the values.
var html = "", i, len = listItemValues.length;
for (i = 0; i < len; i++) {
html += "<span>";
html += listItemValues[i];
html += "</span>";
}
return html; // Return the html content with the sorted values.
};
window.onload = function() {
var additem = id("additem"), sortitems = id("sortitems");
additem.onclick = adding;
sortitems.onclick = sorting;
};
#displayitems span {
border: solid 1px #ccc;
border-radius: 5px;
display: block;
margin: 2px 0;
padding: 4px;
}
<body>
<h1>ToDo List - Date: <span id="today"> </span></h1>
<div id="todolist">
<p>
<input type="button" id="additem" value="Add Item">
</p>
</div>
<hr>
<div>
<p>
<input type="button" id="sortitems" value="Sort and Display Items">
</p>
<p id="displayitems"></p>
</div>
</body>
Hope this helps.