From my understanding it's good practice to keep all your DOM selectors inside an object, because if the html is modified, you only need to change that object instead of looking through the entire code. However, how do you get a class name or a id from that object?
Example of what I used to do.
https://codepen.io/anon/pen/vvLoqJ?editors=1111
What I'am trying to do:
Obviously is not going to work because I attempting to add string with object. But if there is a way to add that string class place so that button 2 would work without modifying elements object. Thank you in advance.
https://codepen.io/anon/pen/WLweom?editors=1111
HTML
<button class = "button--roll">First Roll</button>
<button class = "button--roll-2">Second Roll</button>
SCRIPT
const elements = {
buttonRoll: document.querySelector(".button--roll"),
};
class buttonRoll{
constructor(){
// Properties
this.buttonRoll = elements.buttonRoll;
// Methods
this.events;
}
events(){
let roll = "-2";
// this.buttonRoll + roll.addEventListener('click', () => this.buttonRoll2());
console.log(this.buttonRoll);
}
buttonRoll2(){
console.log("second button is clicked");
}
}
buttonRoll = new buttonRoll;
buttonRoll.events();
in this case, by using your const element :
const elements = {
buttonRoll: document.querySelector(".button--roll"),
};
class buttonRoll {
constructor() {
let base_ClassName = elements.buttonRoll.className;
this.button_1 = elements.buttonRoll;
this.button_2 = document.querySelector('.'+base_ClassName+'-2');
this.button_1.onclick = (e)=>this.button_x_click(e);
this.button_2.onclick = (e)=>this.button_x_click(e);
}
button_x_click(e){
console.log(e.target.className);
}
}
buttonRolls = new buttonRoll();
<button class = "button--roll">First Roll</button>
<button class = "button--roll-2">Second Roll</button>
you're looking for something like that ?
class buttonRoll {
constructor(base_ClassName) {
this.button_1 = document.querySelector('.'+base_ClassName);
this.button_2 = document.querySelector('.'+base_ClassName+'-2');
this.button_1.onclick = (e)=>this.button_1_click(e);
this.button_2.onclick = (e)=>this.button_2_click(e);
}
button_1_click(e){
console.log('button_1_click');
}
button_2_click(e){
console.log('button_2_click');
}
}
buttonRolls = new buttonRoll('button--roll');
<button class = "button--roll">First Roll</button>
<button class = "button--roll-2">Second Roll</button>
Related
I have some To Do-s that are dinamically created by the user:
<div>
<h3 class = 'taskTitle'>do homework </h3>
<p class = 'taskDate'>Expires: 2021.12.31</p>
<input type = button class = 'delBtn' value = 'x'></input>
<input type = button class = 'expandBtn' value = '...'></input>
</div>
<div>
<h3 class = 'taskTitle'>workout </h3>
<p class = 'taskDate'>Expires: 2021.10.11</p>
<input type = button class = 'delBtn' value = 'x'></input>
<input type = button class = 'expandBtn' value = '...'></input>
</div>
**etc.**
On click of the expandBtn a pop up window appears that would contain the title (h3) and the date (p) of the specific To Do.
script:
function showDescription(){
const expandBtns= document.querySelectorAll('.expandBtn')
expandBtns.forEach(btn => {
btn.addEventListener('click', function(event){
let popUp = document.createElement('div')
popUp.classList.add('descriptionBox')
let title = event.target.parentNode.firstChild.textContent **<--says its undefined**
let date = event.target.parentNode.firstChild.textContent **<--says its undefined**
popUp.innerHTML = `
<h3>${title}</h3>
<p class = 'description'> lorem ipsum </p>
<p class = 'dateDescription'>${date}</p>
<input class = 'delDescription' type = button value = 'x'></input>`
const todos = document.querySelector('#todos')
todos.appendChild(popUp)
//close button for popUp
const delDescription = document.querySelectorAll('.delDescription')
delDescription.forEach(btn => {
btn.addEventListener('click', function (event){
event.target.parentNode.remove()
})
})
// alert(document.querySelector('.activeProject').textContent)
})
})
}
So how could I target them? querySelector isn't good either, as I have more than 1 To Do-s. Any help appreciated!
You could add a unique id or class to all the div elements. For example:
<div id="to-do-1"><p>Test</p></div>
<button onclick="myFunction()">Click Me!</button>
<script>
function myFunction() {
document.getElementById("to-do-1").style.display = "inline";
}
</script>
<style>
#to-do-1 {
display: none;
}
</style>
Select all expandBtn
var btn = document.getElementsByClassName("expandBtn")
Create a loop and addEventListener for all of them
for(let i =0; i < btn.length; i++) {
btn[i].addEventListener("click", function () {
let h3 = this.parentNode.getElementsByTagName("h3")[0];
let p = this.parentNode.getElementsByTagName("p")[0];
alert("h3 = "+ h3.innerText + " & p = " + p.innerText);
}
}
now when the user clicking on anyone of them it's will search for h3, p who is belong to the parent of this button
Using .children will get you what you want:
document.addEventListener("click",ev=>{
if (ev.target.className!=="expandBtn") return;
const [name,date]=[...ev.target.parentNode.children].slice(0,2).map(e=>e.textContent)
console.log(name,date);
// further code for popup ...
})
<div>
<h3 class = 'taskTitle'>do homework </h3>
<p class = 'taskDate'>Expires: 2021.12.31</p>
<input type = button class = 'delBtn' value = 'x'></input>
<input type = button class = 'expandBtn' value = '...'></input>
</div>
<div>
<h3 class = 'taskTitle'>workout </h3>
<p class = 'taskDate'>Expires: 2021.10.11</p>
<input type = button class = 'delBtn' value = 'x'></input>
<input type = button class = 'expandBtn' value = '...'></input>
</div>
.firstChild will return the first childNode, which in your case would have been a blank and a line-break and not the <h3> element you expected.
.children on the other hand will return a collection of all child elements (like: <div>, <p>, <span>, ... etc.), the chained .slice(0,2) will slice off the first two elements only.
My code looks like this:
function myFunction(result) {
var json = JSON.parse(result)
var jsonKeys = Object.keys(json)
var items = document.getElementById("items");
var adds = items.getElementById("add");
clearA()
var i;
for (i = 0; i < jsonKeys.length; i++) {
var btn = document.createElement("BUTTON");
console.log(jsonKeys[i]);
btn.innerHTML = jsonKeys[i]
btn.setAttribute("id", jsonKeys[i]);
btn.onclick = function() { run(this.id); }
items.appendChild(btn)
}
}
I can get items and use them but when I try to get the child element "add" I get items.getElementById is not a function
This is the html:
<div id="items">
<div id="add">
<input type="submit" value="add" onclick="foo(add)">
</div>
</div>
Change it to:
var items = document.getElementById("items");
var adds = document.getElementById("add");
Since ids are meant to be unique on a document, only document.getElementById exists. You could use items.querySelector('#id'), but this is probably a manifestation of a larger problem where you have similar HTML structure for multiple elements, with duplicated ids. In this case, it is recommended that you switch to classes and use items.querySelector('.classname').
I have 2 divs with same class but different textContent
I want to extracts its value using eventListners and pass it as a argument to another function
Html Code
<div class = "seasonDeatils__container">
<p class = "seasonYear ">2020</p>
</div>
<div class = "seasonDeatils__container">
<p class = "seasonYear ">2019</p>
</div>
JavaScript Code I tried
var season;
const getSeasonYear = document.querySelectorAll('.seasonDeatils__container');
getSeasonYear.forEach((el)=>{
el.addEventListener('click', ()=>{
season = el.firstElementChild.textContent;
})
})
//I now want to access the 'season' value elsewhere in the code
Just pass the value of season as an argument from inside your click listener function itself to a function elsewhere in your code as follows:
var season;
const getSeasonYear = document.querySelectorAll('.seasonDeatils__container');
getSeasonYear.forEach((el)=>{
el.addEventListener('click', ()=>{
season = el.firstElementChild.textContent;
someOtherFunction(season);
})
})
someOtherFunction = x => {
console.log(x);
alert(x);
}
<div class = "seasonDeatils__container">
<p class = "seasonYear ">2020</p>
</div>
<div class = "seasonDeatils__container">
<p class = "seasonYear ">2019</p>
</div>
I am using lit-html library to render the data into the form.
The program should auto fill the product name upon inputting the product number. I have written the code but I am unable to auto fill the product name field. For the product name, I have used static dummy data within my JavaScript code.
Is there a way to do this using only web components or using library 'lit-html'?
Below you can find my code
import {html, render} from 'lit-html'
class MyApp extends HTMLElement {
constructor() {
super()
this.attachShadow({mode: 'open'});
const forms = () => {
const productNum = new Array();
const productName = new Array();
productNum[0] = 123;
productName[0] = 'Paper';
productNum [1] = 500;
productName[1] = 'Laptop';
function details(products) {
if (products > 50) {
for (let i = 0; i < productNum.length; i++) {
if (products == productNum[i]) {
this.info.product.value = productName[i]
} else {
this.info.product.value = ''
}
}
}
}
return html` <form name = 'info'>
<input type="text" name="product" onkeyup="${details(parseInt(this.value, 10))}" maxlength=3>ProductNum
<input type="text" name="productName" onkeyup="">ProductName
</form>`
}
const template = html`
${forms()}`
render(template, this.shadowRoot)
}
}
window.customElements.define('my-app', MyApp)
Objective: (auto)Fill related Form fields with (product) data
One (native) component way is to let the FORM handle the querying for product data
Communicate productinfo with Events
That way there is no dependency between components (other than an EventName),
and you can have as many related inputs as you need.
Relevant Custom Element code:
<my-form>
<my-input name="productkey"></my-input>
<my-input name="productname"></my-input>
</my-form>
customElements.define("my-form", class extends HTMLElement {
constructor() {
super();
let products = productDatabaseMap();
this.addEventListener("getProduct", evt => {
let detail={
product: products[evt.detail.value],
input: evt.target // input that requested product details
};
dispatchEvent(this, "setProduct", detail);
});
}
})
customElements.define("my-input", class extends HTMLElement {
constructor() {
super();
let input = this.appendChild(document.createElement('input'));
let name = input.placeholder = this.getAttribute('name');
this.onkeyup = evt => dispatchEvent(input, "getProduct", evt.target);
this.closest("my-form").addEventListener("setProduct", evt => {
let product = evt.detail.product;
if (product instanceof Product) input.value = product[name];
else if (evt.detail.input !== input) input.value = '';
});
}
})
Data is stored in a Map with both productkey AND productname as lookup keys
each input keypress sends a "getProduct" Event UP the DOM tree
An Event Listener on my-form gets the product from the lookup Map
The form dispatches a "setProduct" Event with the Product or undefined product
ALL inputs listen for the "setProduct" Event
if a product was returned ALL input fields set the corresponding value
Working JSFiddle: https://jsfiddle.net/WebComponents/L2dcruoh/
If you wrap <my-input> in a shadowRoot you need more boilerplate code
and be aware event.detail then needs composed:true to make it cross shadow boundaries.
And event.target will reference the (last) component it came from... not the input
field that triggered that event
Hollow i have some issue and small problem
i have 3 input fields I need to get values on click from them assign them to object and that object push in to array
can somebody can help ore say where to look info I'm searching on MDN but I can't find correct topic whit examples
1)input value to object and then that object push to array
function $(e) {
return document.querySelector(e);
}
function $$(e) {
return document.querySelectorAll(e);
}
var startBtn = $("send");
startBtn.addEventListener('click', creatTask, false);
function creatTask() {
var addTaskName = $(".task-name"),
addCategory = $(".category"),
addTaskSatus = $(".status");
<!-- task.Taskname = addTaskName.value
task.Category = addCategory.value
task.Status = addTaskSatus.value........... ? -- >
var TaskListArray = [];
var task = {
Taskname: undefined,
Category: undefined,
Status: undefined
}
console.log(task)
}
document.write("message")
Link to jsfiddle with html and javascript
Try setting id or className selector at var startBtn = $("send"); defining TaskListArray outside of creatTask function; setting values directly at creation of task object; use Array.prototype.push() to add current task object to TaskListArray array.
Also, use window.onload event, or place <script> after elements in html for elements queried in DOM to be loaded in document before creatTask is called or startBtn defined
<script>
window.onload = function() {
function $(e) {
return document.querySelector(e);
}
function $$(e) {
return document.querySelectorAll(e);
}
var startBtn = $(".send");
var TaskListArray = [];
startBtn.addEventListener('click', creatTask, false);
function creatTask() {
var addTaskName = $(".task-name"),
addCategory = $(".category"),
addTaskSatus = $(".status");
var task = {
Taskname: addTaskName.value,
Category: addCategory.value,
Status: addTaskSatus.value
}
TaskListArray.push(task)
console.log(task)
}
}
// document.write("message")
</script>
<input class="task-name" name="task" />
<br>
<input class="category" name="category" />
<br>
<input class="status" name="status" />
<br>
<input type="button" class="send" value="send" />