How to implement dynamic buttons html using insertAdjacentHTML JS Method? - javascript

I'm creating a Chrome extension to download videos from a certain site, I need to show the available resolutions buttons in an insertAdjacentHTML, but I don't know how to implement it.
my code:
const list = ['240p', '480p', '720p', '1080p']
const container = document.querySelector('.video-info-container');
container.insertAdjacentHTML('beforebegin',`
<ul class="mlext-container">
<li>AVALIABLE RESOLUTIONS: <span> <div id="container"></div> </span></li>
</ul>`)
In this case, the buttons should be added to the <div id="container"></div> from the code above
I have this code above that creates the buttons in the index.html file inside the body tag if <div id="container"></div> is there,but I want to create them inside the code that was inserted by the insertAjacentHTML method
list.forEach(element => {
document.addEventListener('DOMContentLoaded', function () {
var button = document.createElement('button');
button.type = 'button';
button.innerHTML = element;
button.className = 'btn-styled';
button.id = element
button.onclick = function () {
if (button.id == '240p') {
var linkRequest =
console.log(element)
}
if (button.id == '480p') {
console.log(element)
}
if (button.id == '720p') {
console.log(element)
}
if (button.id == '1080p') {
console.log(element)
}
};
var container = document.getElementById('container');
container.appendChild(button);
}, false);
});
how to do it?

Related

Add Button for Selected Product Cards using JavaScript

I am working with e-commerce site. How do I add a button exclusively to product cards that contain audio file?
var products = document.querySelectorAll('ul.products');
products.forEach(function(product){
var voice = product.querySelectorAll('li.product > div.nv-card-content-wrapper');
voice.forEach(function(item) {
var btn = document.createElement('button');
btn.className = 'play_audio';
btn.textContent = "CLICK TO LISTEN";
btn.setAttribute("type", "button");
btn.addEventListener('click', () => {
item.getElementsByTagName('audio')[0].play();
})
if (!item.getElementsByTagName('audio')){
btn.style.visibility = "hidden";
}
item.appendChild(btn);
});
})
This is the sample page: https://staging.buellairhorns.com/product-category/horns/page/2
Just got it solved. I just need to change my condition from
!item.getElementsByTagName('audio')
to
!item.getElementsByTagName('audio')[0]

How to prevent modal event listener from affecting other items?

I'm currently working on a Library app where a user can track unread and read books. I have it setup where when you click a book a modal pops up with the title, author, and buttons allowing you to mark the book as read or completely delete it.
I'm trying to fix a problem where opening and closing more than one modal and then clicking the delete button will delete all the items you previously clicked.
Here's the delete function -
Book.prototype.delete = function() {
myLibrary = myLibrary.filter((e) => {
return e !== this;
});
};
Here's how I'm opening each modal -
const render = () => {
const booksUnreadList = document.getElementById('unread');
const booksReadList = document.getElementById('read');
booksUnreadList.innerHTML = 'Unread';
booksReadList.innerHTML = 'Read';
myLibrary.forEach((book) => {
const li = document.createElement('li');
li.className = 'book';
book.read === 'Read'
? booksReadList.appendChild(li)
: booksUnreadList.appendChild(li);
li.innerHTML = book.info();
li.addEventListener('click', function handler() {
openBookModal(book);
});
});
And then the modal itself -
function openBookModal(book) {
document
.getElementById('book-modal-mark-complete')
.removeEventListener('click', markReadHandler);
document
.getElementById('book-modal-delete')
.removeEventListener('click', deleteHandler);
bookForm.style.display = 'none';
toggleForm.style.backgroundColor = '#978de0';
toggleForm.innerHTML = 'Add Book';
const bookModal = document.getElementById('book-modal');
bookModal.style.display = 'grid';
document.getElementById('book-modal-title').innerHTML = book.title;
document.getElementById('book-modal-author').innerHTML = 'By ' + book.author;
document
.getElementById('book-modal-mark-complete')
.addEventListener('click', markReadHandler);
function markReadHandler() {
book.read = 'Read';
render();
bookModal.style.display = 'none';
}
document
.getElementById('book-modal-delete')
.addEventListener('click', deleteHandler);
function deleteHandler() {
book.delete();
render();
bookModal.style.display = 'none';
}
document.getElementById('book-modal-close').addEventListener('click', () => {
bookModal.style.display = 'none';
});
}
Here's a jsfiddle of everything, to recreate the problem just open and close 2+ books and then delete 1 of them.
https://jsfiddle.net/Spawn_Bot/w6j4b8Lh/4/
Thanks!
You could store the currently selected book in the currentBook variable, move the modal event handlers outside the openBookModal() function and in the event handlers you could delete the currentBook:
let currentBook = {};
...
function openBookModal(book) {
currentBook = book;
...
}
document
.getElementById('book-modal-mark-complete')
.addEventListener('click', markReadHandler);
function markReadHandler() {
currentBook.read = 'Read';
render();
bookModal.style.display = 'none';
}
document
.getElementById('book-modal-delete')
.addEventListener('click', deleteHandler);
function deleteHandler() {
currentBook.delete();
render();
bookModal.style.display = 'none';
}
Here's the demo: https://jsfiddle.net/k6z08m2q/

Remove dynamically created elements by class name Javascript

So, in plain terms I am creating a Chrome Extension that so far can only save links from the internet but not delete them. What I want to add is a "remove" button for deleting unwanted links. So far I haven't got that to work.
The buttons I want to remove are added using JavaScript. Each new block of HTML features a "remove" button but clicking that button does nothing. I have tried binding listeners to each element using a for loop but that doesn't seem to work.
The code runs without errors and I'm certain that the issue is a slight oversight but I have only just started using JavaScript so I'm lost for solutions at the moment.
I have included all the code because I don't want to leave out anything that might be imperative to finding a solution.
It starts with the code for adding a link, followed by removing a single link and then removing all links at once. Thank you all for any help, really want to get this working.
https://github.com/mmmamer/Drop Repository for the rest of the code. Mainly popup.html and popup.css.
var urlList = [];
var i = 0;
document.addEventListener('DOMContentLoaded', function() {
getUrlListAndRestoreInDom();
// event listener for the button inside popup window
document.getElementById('save').addEventListener('click', addLink);
});
function addLink() {
var url = document.getElementById("saveLink").value;
addUrlToListAndSave(url);
addUrlToDom(url);
}
function getUrlListAndRestoreInDom() {
chrome.storage.local.get({
urlList: []
}, function(data) {
urlList = data.urlList;
urlList.forEach(function(url) {
addUrlToDom(url);
});
});
}
function addUrlToDom(url) {
// change the text message
document.getElementById("saved-pages").innerHTML = "<h2>Saved pages</h2>";
var newEntry = document.createElement('li');
var newLink = document.createElement('a');
var removeButton = document.createElement('button');
removeButton.textContent = "Remove";
//removeButton.createElement('button');
removeButton.type = "button";
removeButton.className = "remove";
newLink.textContent = url;
newLink.setAttribute('href', url);
newLink.setAttribute('target', '_blank');
newEntry.appendChild(newLink)
newEntry.appendChild(removeButton);
newEntry.className = "listItem";
document.getElementById("list").appendChild(newEntry);
}
function addUrlToListAndSave(url) {
urlList.push(url);
saveUrlList();
//}
}
function saveUrlList(callback) {
chrome.storage.local.set({
urlList
}, function() {
if (typeof callback === 'function') {
//If there was no callback provided, don't try to call it.
callback();
}
});
}
// remove a single bookmark item
document.addEventListener('DOMContentLoaded', function() {
getUrlListAndRestoreInDom();
var allButtons = document.getElementsByClassName('remove');
function listenI(i) {
allButtons[i].addEventListener('click', () => removeMe(i));
}
for (var i = 0; i < allButtons.length; i++) {
listenI(i);
}
});
function removeMe(i) {
var fullList = documents.getElementsByClassName('listItem');
listItem[i].parentNode.removeChild(listItem[i]);
}
//remove all button
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("remove-all").addEventListener('click', function() {
var removeList = document.getElementsByClassName("listItem");
while(removeList[0]) {
removeList[0].parentNode.removeChild(removeList[0]);
}
})
});
chrome.storage.local.get() is asynchronous. So when you try to add the event listeners to the Remove buttons, they're not in the DOM yet.
You can add the listener in the addUrlToDom() function instead. That way you'll also add the event listener when you create new buttons.
function addUrlToDom(url) {
// change the text message
document.getElementById("saved-pages").innerHTML = "<h2>Saved pages</h2>";
var newEntry = document.createElement('li');
var newLink = document.createElement('a');
var removeButton = document.createElement('button');
removeButton.textContent = "Remove";
//removeButton.createElement('button');
removeButton.type = "button";
removeButton.className = "remove";
newLink.textContent = url;
newLink.setAttribute('href', url);
newLink.setAttribute('target', '_blank');
newEntry.appendChild(newLink)
newEntry.appendChild(removeButton);
removeButton.addEventListener("click", function() {
var anchor = this.previousElementSibling;
var url = anchor.getAttribute("href");
removeUrlAndSave(url);
this.parentNode.remove();
});
newEntry.className = "listItem";
document.getElementById("list").appendChild(newEntry);
}
function removeUrlAndSave(url) {
var index = urlList.indexOf(url);
if (index != -1) {
urlList.splice(index, 1);
saveUrlList();
}
}

Call prototype function from onclick event, when button is added dynamically

I have two prototype functions showPopup and buildView. In buildView, I am generating a dynamic HTML with a button and would like to call showPoup when button is clicked. However, when button is clicked, it throws
Error: The value of the property 'showPopup' is null or undefined, not
a Function object
MyEditor.prototype.buildView = function(id) {
document.getElementById("myView").innerHTML = "<input type='button' value='Edit' onclick='showPopup(getName(id), getPlace(id))' />";
}
MyEditor.prototype.showPopup = function(name, place) { }
I even tried using onclick='MyEditor.showPopup(getName(id), getPlace(id))', didn't work either.
Because you have to call this.showPopup(), which is only possible if you build up the DOM manually:
MyEditor.prototype.buildView = function(id) {
const button = document.createElement("input");
button.type = "button";
button.value = "Edit";
button.onclick = (evt) => {
this.showPopup(getName(id), getPlace(id));
};
document.getElementById("myView").appendChild(button);
}
Create your element via document.createElement()
Attach a click event listener to the element using an arrow function to preserve the this context
Empty out the #myView element of all child nodes
Append the element to your #myView element
MyEditor.prototype.buildView = function(id) {
const btn = document.createElement('input')
btn.type = 'button';
btn.value = 'Edit'
btn.addEventListener('click', () => {
this.showPopup(getName(id), getPlace(id))
}, false)
// empty out #myView
const view = document.getElementById('myView')
while (view.firstChild) {
view.removeChild(view.firstChild)
}
view.appendChild(btn)
}
If you want to build element by html text, you need do something like this.
MyEditor = function() {};
MyEditor.prototype.buildView = function(id) {
document.getElementById("myView").innerHTML = "<input type='button' value='Edit' onclick='editor.showPopup(\"name\", \"id\")' />";
}
MyEditor.prototype.showPopup = function(name, place) {
console.log(name)
}
var editor = new MyEditor()
editor.buildView();
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"></head>
<body>
<div id="myView"></div>
</body>
</html>

Is there a way to refactor this JS code so that I am not repeating myself so much?

I'm very new to JS and struggling to refactor the following code. It functions as expected and opens and closes modal windows, but it is not particularly dry to say the least...
// Open modal windows
document.querySelector('#modal-btn1').addEventListener('click',
function() {
document.querySelector('.modal1').style.display = 'block';
document.querySelector('body').style.overflow = 'hidden';
});
document.querySelector('#modal-btn2').addEventListener('click',
function() {
document.querySelector('.modal2').style.display = 'block';
document.querySelector('body').style.overflow = 'hidden';
});
document.querySelector('#modal-btn3').addEventListener('click',
function() {
document.querySelector('.modal3').style.display = 'block';
document.querySelector('body').style.overflow = 'hidden';
});
document.querySelector('#modal-btn4').addEventListener('click',
function() {
document.querySelector('.modal4').style.display = 'block';
document.querySelector('body').style.overflow = 'hidden';
});
// Close modal windows
document.querySelector('.close-box1').addEventListener('click',
function () {
document.querySelector('.modal1').style.display = 'none';
document.querySelector('body').style.overflow = 'visible';
});
document.querySelector('.close-box2').addEventListener('click',
function () {
document.querySelector('.modal2').style.display = 'none';
document.querySelector('body').style.overflow = 'visible';
});
document.querySelector('.close-box3').addEventListener('click',
function () {
document.querySelector('.modal3').style.display = 'none';
document.querySelector('body').style.overflow = 'visible';
});
document.querySelector('.close-box4').addEventListener('click',
function () {
document.querySelector('.modal4').style.display = 'none';
document.querySelector('body').style.overflow = 'visible';
});
Any pointers in the right direction would be much appreciated.
You can use classes to create your events and link each click event to its modal using custom attributes
see code sample
document.querySelectorAll('.modal-btn').forEach(function(item){
item.addEventListener('click',
function(e) {
var target = item.getAttribute("data-modal");
document.querySelector(target).style.display = 'block';
document.querySelector('body').style.overflow = 'hidden';
});
})
.modal {
display:none;
background:black;
width:150px;
height:50x;
color:white;
}
<button class="modal-btn" data-modal="#modal1">open modal 1</button>
<button class="modal-btn" data-modal="#modal2">open modal 2</button>
<button class="modal-btn" data-modal="#modal3">open modal 3</button>
<div id="modal1" class="modal">Modal 1</div>
<div id="modal2" class="modal">Modal 2</div>
<div id="modal3" class="modal">Modal 3</div>
const ID = "#";
const CLASS = ".";
const addEvent = (idOrClass, name, elementsLength, modalDisplay, bodyOverflow) => {
for(let i=1; i <= elementLength; i++){
document.querySelector(`${idOrClass}${name}${i}`).addEventListener('click', () => {
document.querySelector(`.modal{i}`).style.display = modalDisplay;
document.querySelector('body').style.overflow = bodyOverflow;
});
}
}
addEvent(ID, 'modal-btn', 4, 'block', 'hidden');
addEvent(CLASS, 'close-box', 4, 'none', 'visible');
Not the prettiest, but this is what i could think of at the top of my head. Usually you would use a framework like Bootstrap to handle modals for you
You can easily minimize how much you repeat code by writing functions that use variables. This is the beauty of programming!
For example, give all your buttons some sort of descriptor that you can use to uniquely identify which modal they should open, then you can write a single event listener to open the correct one.
Example:
If you have elements and modals like this:
<button class='modal-button' data-target-modal='modal-1'>
Open Modal 1
</button>
<div id='modal-1' class='modal'>
Hi I am modal 1
</div>
Then you can have a single function to power all of them like this:
document.addEventListener('click', (event) => {
let clickedEl = event.target;
// do this when we click a modal-button
if(clickedEl.classList.contains('modal-button')) {
// get the id of the modal via getAttribute
let modalId = clickedEl.getAttribute('data-target-modal');
// now get a reference to the actual modal html element
let modalEl = document.getElementById(modalId);
// open it!
modalEl.classList.add('open');
}
else
if(clickedEl.classList.contains('modal-close-button')) {
// do something similar here for closing!
}
})
https://jsfiddle.net/ryc8xzan/

Categories

Resources