what is the right way to write this code? - javascript

im pretty sure the
tabelist.innerHTML = '<option>invalid value</option>'
isn't the best way to make an element and insert it in another one, but how i am supposed to do this if is not this way?
let submit = document.querySelector('input#submit')
let tabelist = document.querySelector('select#tabe')
submit.addEventListener('click', clicar)
function clicar(){
let tabenumber = 1
let number = Number(document.querySelector('input#number').value)
if(number == ''){
tabelist.innerHTML = '<option>invalid value</option>'
}else{
tabelist.innerHTML = ''
for(number*tabenumber; tabenumber <=10; tabenumber++){
tabelist.innerHTML += `<option>${number} x ${tabenumber} = ${number*tabenumber} </option>`
}
}
}

.innerHTML is valid, but should only be used as a last resort because it has potential side effects of:
wiping out event handlers that were set on elements that are now
being replaced
slowing down the rendering of the page because the HTML parser
must parse the new content
potentially exposing a security hole by allowing malicious script
to execute
Another approach would be to use the Document Object Model to create, configure and inject an element:
const list = document.querySelector("select");
// Create new element
const option = document.createElement("option");
// Configure new element
option.textContent = "Item 1";
// Inject into existing element
list.appendChild(option);
<select>
</select>

Related

Custom Javascript not working in Wordpress

My intent is to add an excerpt to each portfolio card within a grid (currently, these only show an image, title and category).
I found a way to insert the excerpt into a card and to iterate through all the cards, but excerpt is not inserting into all of the cards even though the loop is working as expected (logging each iteration). The excerpt will only insert into one card if I specific a specific index of the targetsArray. I left this line commented out for reference.
window.onload = function() {
let targets = document.querySelectorAll('.entry-title');
let newElem = document.createElement('p');
let excerpt = 'This will be the excerpt...';
newElem.innerHTML = excerpt;
let targetsArray = [];
for (let i = 0; i < targets.length; i++) {
targetsArray.push(targets[i]);
}
targetsArray.forEach(target => {
console.log(target);
target.parentNode.insertBefore(newElem, target.nextSibling);
});
// targetsArray[1].parentNode.insertBefore(newElem, targetsArray[1].nextSibling);
};
Note: If you're wondering why I didn't use a simplier method for converting the nodes list into an array, it is because they weren't working.
I tried
const targets = [...document.querySelectorAll(".entry-title")];
and...
Array.from(targets)
For reference this is the page I'm trying to make these changes to
equipourkids.org
I don't know if you are trying to do it with pure JS for a specific reason but Wordpress already loads jQuery by default (if you didn't remove it) and doing that with jQuery should be much more simple then that.
let targets = $('.entry-title');
let newElem = $('<p>This will be the excerpt...</p>')
targets.each(function (idx, item){
$(item).parent().insertBefore(newElem);
});
I just don't understand where exactly you want to insert those exceprt based on your HTML structure. Should that be inside entry-info or what?

How can I create a syntax like vue js in vanilla JavaScript?

<div id="">
<span>{{msg}}</span>
</div>
Let's think msg is variable of JavaScript and now I want to get the parent tag of {{msg}} and push a new value by innerHTML, here {{msg}} working as an identity.
demo JavaScript example:
<script>
var msg = "This is update data";
{{msg}}.parentElement.innerHTML=msg;
</scritp>
This is not actual JavaScript code, only for better understanding.
You can use jquery easily to find that element and then replace the text
var msg = "This is update data";
$(`span:contains(${msg})`).html("Its New");
In javascript:
var spanTags = document.getElementsByTagName("span");
var msg = "This is update data";
var found;
for (var i = 0; i < spanTags.length; i++) {
if (spanTags[i].textContent == msg) {
found = spanTags[i];
break;
}
}
Now, you have found that element in found and you can now change its text
if (found) {
found.innerHTML = "New text";
}
The simplest approach is to treat the entire document as a string and then re-parse it when you're done.
The .innerHTML property is both an HTML decompiler and compiler depending on weather you're reading or writing to it. So for example if you have a list of variables that you want to replace in your document you can do:
let vars = {
msg: msg, // pass value as variable
test_number: 10, // pass value as number
test_str: 'hello' // pass value as string
};
let htmlText = document.body.innerHTML;
// find each var (assuming the syntax is {{var_name}})
// and replace with its value:
for (let var in vars) {
let pattern = '\\{\\{\\s*' + var + '\\s*\\}\\}';
let regexp = new RegExp(pattern, 'g'); // 'g' to replace all
htmlText = htmlText.replace(regexp, vars[var]);
}
// Now re-parse the html text and redraw the entire page
document.body.innerHTML = htmlText;
This is a quick, simple but brutal way to implement the {{var}} syntax. As long as you've correctly specified/designed the syntax to make it impossible to appear in the middle of html tags (for example <span {{ msg > hello </ }} span>) then this should be OK.
There may be performance penalties redrawing the entire page but if you're not doing this all the time (animation) then you would generally not notice it. In any case, if you are worried about performance always benchmark your code.
A more subtle way to do this is to only operate on text nodes so we don't accidentally mess up real html tags. The key to doing this is to write your own recursive descent parser. All nodes have a .childNodes attribute and the DOM is strictly a tree (non-cyclic) so we can scan the entire DOM and search for the syntax.
I'm not going to write complete code for this because it can get quite involved but the basic idea is as follows:
const TEXT_NODE = 3;
let vars = {
msg: msg, // pass value as variable
test_number: 10, // pass value as number
test_str: 'hello' // pass value as string
};
function walkAndReplace (node) {
if (node.nodeType === TEXT_NODE) {
let text = node.nodeValue;
// Do what you need to do with text here.
// You can copy the RegExp logic from the example above
// for simple text replacement. If you need to generate
// new DOM elements such as a <span> or <a> then remove
// this node from its .parentNode, generate the necessary
// objects then add them back to the .parentNode
}
else {
if (node.childNodes.length) {
for (let i=0; i<node.childNodes.length; i++) {
walkAndReplace(node.childNodes[i]); // recurse
}
}
}
}
walkAndReplace(document.body);

How to copy contents of <textarea> into a variable with an event listener?

I am trying to create a website that allows the user to add custom HTML and CSS in real time. This is easy enough. However, I need to be able to evaluate classes and id(s), so they don't mess with anything. I am using the "input" event listener to detect changes, but it doesn't recognize changes from 'pasting' and 'highlighting + deleting.' What can I do to fix this?
let buffer = "";
let new_html = document.getElementsByClassName("insert-new-content");
let preview = document.getElementById("new-content-preview");
let update_html = function (letter){
//Used to recognize when a letter is deleted
if(!letter.data)buffer = buffer.slice(0, buffer.length - 1);
//appends new information to buffer for evaluation
else buffer += letter.data;
};
new_html[0].addEventListener("input", update_html);
new_html[1].addEventListener("input", update_html);
You can just use event.srcElement.value;. It returns the text of the textarea.
function update_html(event){
buffer = event.srcElement.value;
}

How to use a same image multiple times by loading it only once when I need different id for every element

I am a newbie to programming and web developing. The project I am doing is only for practice, if my approach seems ameteur to you, please suggest any better options.
I am trying to develop a parking lot booking system. And in the UI, I want to show all the empty/filled slots (like it is while booking movies or bus tickets).
I couldn't find a top view icon of a car, so I thought of using an image instead of icon.
But as of the image, if I use say 50 images on a single page, the page will get very heavy.
But one important thing is that I need all the elements as seperate entities, only then I will be able to book them with their id(unique address). So I want 50 different divs with seperate distinct ids but want to use only one image for all the slots, or a maximum of 2 different images(keeping the directions in mind).
how to display same image multiple times using same image in javascript
I went through this answer, and found a piece of code that might be useful:
var imgSrc = 'http://lorempixel.com/100/100';
function generateImage() {
var img = document.createElement('img')
img.src = imgSrc;
return img;
}
for (var i = 0; i < 20; i++ ) {
document.body.appendChild(generateImage());
}
While I can make use of a function and a loop in javascript to create as many copies of one image, I don't know how to alot them to the different div tags with distinct ids.
use a function :)
const addMessage = (element, msg, cls) => {
const patt = new RegExp("<");
const messageElement = document.createElement("div");
if (patt.test(msg)) {
messageElement.innerHTML = msg
} else messageElement.textContent = msg;
if (cls) messageElement.classList.add(cls);
element.appendChild(messageElement);
}
const imgPath = "/somepath";
const body = document.querySelector("body");
addMessage(body, `<img src=${imgPath} class="whatever">`, "img1"); //creates new divs with classes. the 3rd arg is optional
the best approach for this is the client side already receiving all this content as a string but as it made clear that it is for study I deduce that it is not the intention to use back end to solve this problem
let allContent = '';
for (var i = 0; i < 20; i++ ) {
allContent += `<div class="wrapper-image"><img src="/path"></div>`
}
document.getElementById('idWrapper').innerHTML = allContent;
speaking in performace the browser will only download the image once, so you can use it as many times as you like, which is disruptive to the changes you make in the DOM (remove, add or edit a content)
In my example you create all the content to be displayed on the page and then add it in a single time, it is not too bad if it is performace but the ideal is to do it on the back side
in the DIV you can put an image address of a variable to do some logical type this:
let allContent = '';
let imgOne = '/oneimg';
let imgOne = '/twoImg';
for (var i = 0; i < 20; i++ ) {
if(i>10){
allContent += `<div class="wrapper-image"><img src="${imgOne}"></div>`
}else {
allContent += `<div class="wrapper-image"><img src="${twoImg}"></div>`
}
}
document.getElementById('idWrapper').innerHTML = allContent;

XPathResult and invalid iterator state

I have a relatively large (500-100 rows) HTML table with a bunch of <a> elements. I would like to add a <select> to the top of the page, and populate it by creating an <option> for each <a> in the table.
My first approach looked something like this:
var initSelect = function () {
var select = document.getElementById('mySelect');
var items = document.evaluate('//a', document, null, XPathResult.ANY_TYPE, null);
var item = items.iterateNext();
while (item) {
var elem = document.createElement("option");
var val = document.createAttribute("value");
val.value = elem.nodeValue;
elem.setAttributeNode(val);
elem.innerHTML = item.innerHTML;
select.appendChild(elem);
item = items.iterateNext();
}
};
window.onload = initSelect;
As soon as I tried to appendChild() to the <select> I got an UncaughtInvalidStateError. I figured that modifying the DOM was invalidating my XPathResult iterator, so I tried to add all of the <option> elements to an array first, and then appending them after iterating through all of the results.
var initSelect = function () {
var select = document.getElementById('src_select');
var items = document.evaluate('//a', document, null, XPathResult.ANY_TYPE, null);
var elems = [];
var item = items.iterateNext();
while (item) {
var elem = document.createElement("option");
var val = document.createAttribute("value");
val.value = elem.nodeValue;
elem.setAttributeNode(val);
elem.innerHTML = item.innerHTML;
elems.push(elem);
item = items.iterateNext();
}
for (var i = 0; i < elems.length; i++) {
select.appendChild(elems[i]);
}
};
window.onload = initSelect;
If I step through the code in the debugger, I see items.invalidIteratorState go to true after executing the elem.innerHTML = item.innerHTML line. Then I get the same error on the next call to items.iterateNext().
The first thing I'd like to get working is to just see the <select> populated. After that, the goal is to be able to select an element in the drop down, and have the page navigate to the same link that the corresponding <a> element would have taken me to.
This is the first JavaScript I've written, so I appreciate any and all feedback. At this point, I'm looking for a pure JavaScript solution. Once I get it working I'm going to try to pull JQuery in and revise it.
document.links gives you all a href elements in the document so there is no need to use the XPath API to access those elements. And if you are looking for elements in a particular parent then use e.g. document.getElementById('foo').getElementsByTagName('a') to find all a elements in that element with id attribute being foo. I don't see why you would need the DOM Level 3 XPath API for that, which is not supported in IE anyways. And neither document.links nor the result of getElementsByTagName can be invalidated like an XPath iterator result.
If you really want to use the XPath API then try a snapshot as the result type, it should not fail the way the iterator fails due to document manipulation.

Categories