Remove parent element using ES6 - javascript

Here is an attempt to remove parent div. Why it doesn't work?
var images = document.querySelector('.gallery');
images.addEventListener('click', removeClickedImage);
const hasClass = (el, test) => el.classList.contains(test);
const removeClickedImage = ({ target }) => {
if (hasClass(target, 'remove')) {
target.parentNode.remove();
}
};
<div class="gallery">
<div class="image">
<img src="foo.jpg">
<button class="remove">x</button>
</div>
<div class="image">
<img src="bar.png">
<button class="remove">x</button>
</div>
</div>

Your problem is that const functions (along with anything else initialized with const or let) do not get hoisted: at the moment you add the listener, removeClickedImage has not been defined yet. Add the listener after the function has been defined, and it works just fine. The only time you can rely on hoisting like that is when the variable in question is a function defined via a function declaration, like function fnName() {.
const hasClass = (el, test) => el.classList.contains(test);
const removeClickedImage = ({
target
}) => {
if (hasClass(target, 'remove')) {
target.parentNode.remove();
}
};
var images = document.querySelector('.gallery');
images.addEventListener('click', removeClickedImage);
<div class="gallery">
<div class="image">
<img src="foo.jpg">
<button class="remove">x</button>
</div>
<div class="image">
<img src="bar.png">
<button class="remove">x</button>
</div>
</div>

you have to declare the function before calling it when you use const, see : Cant access lexical declaration before init
const removeClickedImage = ({ target }) => {
if (hasClass(target, 'remove')) {
target.parentNode.remove();
}
};
var images = document.querySelector('.gallery');
images.addEventListener('click', removeClickedImage);
const hasClass = (el, test) => el.classList.contains(test);
<div class="gallery">
<div class="image">
<img src="foo.jpg">
<button class="remove">x</button>
</div>
<div class="image">
<img src="bar.png">
<button class="remove">x</button>
</div>
</div>

Related

Adding div container with class name and html content with JavaScript

I'm looking for a way to add a div container using template literals. for example.
I have a div in my index.html
<div class="bag">
</div>
Every time the user adds a new item to the bag the following divs' get added inside the bag like so...
<div class="bag">
<div class="bag__item"> // <--- added here
<div class="wrapper--within">
<img src="./assets/images/cookie5-small.jpg" alt="" />
<h3 class="bag__unit-price">$5</h3>
<div class="bag__quantity-container">
<div class="bag__minus-sign"></div>
<h3 class="bag__quantity-container__quantity">2</h3>
<div class="bag__plus-sign-middle"></div>
<div class="bag__plus-sign-center"></div>
</div>
<div class="bag__total-price-container">
<img
class="bag__trash-icon"
src="./assets/images/trash-small.png"
alt=""
/>
<h2 class="bag__total-price">$10</h2>
</div>
</div>
</div> // <-- to here
</div>
In my javascript I target my bag container
class Cart {
constructor() {
this.cartContainer = document.querySelector(".bag");
this.events();
}
events() {
this.updateCart();
}
updateCart() {
let newItemDiv = document.createElement("div")
newItemDiv.className = "bag__item"
newItemDiv.createElement("div")
}
}
export default Cart;
I was originally planning to add each div individually but i would like a way where i can do something like..
updateCart() {
let newItemDiv = document.createElement("div")
add `<div class="bag__item"> // <--- added here
<div class="wrapper--within">
<img src="./assets/images/cookie5-small.jpg" alt="" /> // <---image will change depending on item added
<h3 class="bag__unit-price">$5</h3> // price will change depending on item added..
<div class="bag__quantity-container">
<div class="bag__minus-sign"></div>
<h3 class="bag__quantity-container__quantity">2</h3>
<div class="bag__plus-sign-middle"></div>
<div class="bag__plus-sign-center"></div>
</div>
<div class="bag__total-price-container">
<img
class="bag__trash-icon"
src="./assets/images/trash-small.png"
alt=""
/>
<h2 class="bag__total-price">$10</h2>
</div>
</div>
</div> `
}
Is this something that can be done?
In your updateCart() method you can write
updateCart() {
let newItemDiv = document.createElement("div")
newItemDiv.className = "bag__item"
newItemDiv.innerHTML = `your markup here with the whole div hierarchy`;
}
You can do this.
If you already added the div.bad
document.getElementsByClassName("bag").innerHTML = `<div> </div>`
or
var elemt = document.createElement("div")
elemt.innerHTML = `<div> </div>`
You can do it like this: (I implemented below example by Cart class because in your question you've been using Cart class to create new Item and I consider that using this class is mandatory, there are other ways to acheive below result with less lines of code)
class Cart {
constructor(img, price) {
this.img = img;
this.price = price;
this.cartContainer = document.querySelector('.bag');
this.events();
}
getTemplate() {
const template = `<div class="bag__item">
<div class="wrapper--within">
<img src="${this.img}" alt="" />
<h3 class="bag__unit-price">${this.price}</h3>
<div class="bag__quantity-container">
<div class="bag__minus-sign"></div>
<h3 class="bag__quantity-container__quantity">2</h3>
<div class="bag__plus-sign-middle"></div>
<div class="bag__plus-sign-center"></div>
</div>
<div class="bag__total-price-container">
<img
class="bag__trash-icon"
src="./assets/images/trash-small.png"
alt=""
/>
<h2 class="bag__total-price">$10</h2>
</div>
</div>
</div> `;
return template;
}
events() {
this.updateCart();
}
updateCart() {
const template = this.getTemplate();
let newItemDiv = document.createElement('div');
this.cartContainer.append(newItemDiv);
newItemDiv.outerHTML = template;
}
}
// sample img, price (You can set different values for img, price when you want to create new one, this static content is just for example)
const img = 'https://fakeimg.pl/350x200/000000/?text=Image1';
const price = '100$';
function addBag(){
new Cart(img, price);
}
<button onClick="addBag()">click me</button>
<div class="bag">ba continaer:</div>

Changing innerHTML

I am trying to change the innerHTML of a page twice, more explanation, I am trying to make a single page like app. I'm a newbie. I want to change the inner HTML content of the section after one click then get the classList of the changed inner HTML then change it again, but it does not seem to work, I don't know what I am doing wrong.
my thought process for the code is below
select the whole container which is the features container
on click, change the container innerHTML
on click of the changed container innerHTML, change the inner HTML again but It doesn't work, it keeps giving me the first innerHTML but when i do not display the main container that works, how can i solve this?
const hold = document.querySelector('#features');
const holds = document.querySelector('.features');
let hel;
hold.addEventListener('click', function() {
holds.innerHTML = `<div class="ddd">h is here </div>`;
// const self = this;
hel = document.querySelector('.ddd');
// console.log(hel.innerText);
hel.addEventListener('click', function() {
// holds.style.display = 'none';
// this.style.display = 'none';
holds.innerHTML = '<div class="q">mess</div>';
console.log(this);
});
});
<section id="features" class="features section-hidden">
<div class="container container-pal1">
<h2 class="features-description highlight">Features</h2>
<div class="features-contain">
<div class="features-text">
<h3 class="features-header">
We are here to provide you with the
<span class="features-highlight">Best</span> services
</h3>
<p class="features-title">
Everything you need in a modern bank and more, get on our waiting list today by clicking the button below
</p>
<a href="" class="hero-cta-1 features-button">View our services <img src="./assets/arrow-right.svg" alt="" />
</a>
</div>
<div class="features-props">
<div class="features-list">
<div class="features-item">
<img src="./assets/fast-delivery.svg" alt="" />
<h5>Swift Delivery 🚀</h5>
<p>No late transfer, get it instantly</p>
</div>
<div class="features-item">
<img src="./assets/0-fees.svg" alt="" />
<h5>$0 Fee's</h5>
<p>No fees on your account like the other banks</p>
</div>
<div class="features-item">
<img src="./assets//0-interest.svg" alt="" />
<h5>Interest &percnt;</h5>
<p>
Interest when applying for loans depends on your agreement from the bank
</p>
</div>
<div class="features-item">
<img src="./assets/no-credit-check.svg" alt="" />
<h5>Credit Card</h5>
<p>Credit cards available at your demand</p>
</div>
<div class="features-item">
<img src="./assets/chat-support.svg" alt="" />
<h5>Chat Support</h5>
<p>Chat with a company representative anytime</p>
</div>
<div class="features-item">
<img src="./assets/fixed-payment-option.svg" alt="" />
<h5>Fixed Payment Option</h5>
<p>Payment Options will be provided</p>
</div>
</div>
</div>
</div>
</div>
</section>
Here's a simple example how to switch elements that already exist in the DOM.
Use a data-* attribute to reference the desired ID element to show.
Use classList.toggle to switch the Elements.
const ELS_pages = document.querySelectorAll(".page");
const ELS_buttons = document.querySelectorAll("[data-page]");
const goToPage = (id) => {
ELS_pages.forEach(EL => EL.classList.toggle("u-none", EL.id !== id));
};
ELS_buttons.forEach(EL => EL.addEventListener("click", () => {
goToPage(EL.dataset.page);
}));
nav {display: flex;} nav a {color: #00f; padding: 5px 10px; cursor: pointer; }
/* Utility classes */
.u-none {display: none;}
<div class="page" id="page-login">
<h1>Welcome</h1>
<button type="button" data-page="page-main">ENTER</button>
</div>
<div class="page u-none" id="page-main">
<nav>
<a data-page="page-settings">User Settings</a>
<a data-page="page-login">Logout</a>
</nav>
<h1>MAIN PAGE</h1>
</div>
<div class="page u-none" id="page-settings">
<nav>
<a data-page="page-main">Back to Main</a>
<a data-page="page-login">Logout</a>
</nav>
<h1>SETTINGS PAGE</h1>
</div>
This is basic, and does not change the URI address in the browser. To achieve that some more code should be added to handle such case.
Try keeping a flag(if there are only two different data you want to show) and based on the flag show data or a counter
const hold = document.querySelector('#features');
let count = 0;
hold.addEventListener('click', function() {
switch (count){
case 0:
holds.innerHTML = `<div class="ddd">h is here </div>`;
case 1:
holds.innerHTML = `<div class="ddd">now some other is here </div>`
};
});
and please provide more info for the remaining answer
Simply run your second innerHTML code after the next repaint using requestAnimationFrame and it will work.
const hold = document.querySelector("#features");
const holds = document.querySelector(".features");
let hel;
hold.addEventListener("click", function (e) {
e.preventDefault();
holds.innerHTML = `<div class="ddd">h is here </div>`;
// const self = this;
hel = document.querySelector(".ddd");
// console.log(hel.innerText);
hel.addEventListener("click", function () {
// holds.style.display = 'none';
// this.style.display = 'none';
requestAnimationFrame(() => {
holds.innerHTML = '<div class="q">mess</div>';
});
console.log(this);
});
});
if you need further information about why it's happening read this article.

How to escape attribute for Javascript Template String?

The snippet is
function addTabItems(tab, items) {
const tabItems = items.map((item) => `
<div class="bvb-cmp-grid__item">
<div class="bvb-comp-grid__item-head">
<img alt="grid-item" src="${item['image']}" class="bvb-cmp-grid__item-img">
<div class="bvb-cmp-grid__item-title">${item['title']}</div>
</div>
<div class="bvb-comp-grid__item-blocks">
${item['items'].map((block) => `
<div class="bvb-comp-grid__item-block">
<div class="bvb-comp-grid__item-block-title">${block['title']}</div>
<div class="bvb-comp-grid__item-block-content">${block['content']}</div>
</div>
`).join('')}
</div>
</div>
`).join('');
const $tabContent = $(`[data-bvb-cmp-grid-tab-content="${tab}"]`);
$tabContent.append(tabItems);
}
Need to achieve - building template by correct way.
How to escape attribue value src="${item['image']}" for preventing XSS atack?

Removing images using event handlers

I really can't figure out how to solve this problem. Here is the question and the original code.
Question: Implement the setup function that registers a click event
handler and implements the following logic: When the button of class
remove is clicked, its parent element should be removed from the
gallery.
function setup() {
**//IM SUPPOSED TO PUT MY CODE ONLY IN THIS PART//**
}
// Example case.
document.body.innerHTML = `
<div class="image">
<img src="firstimage.jpg" alt="First">
<button class="remove">X</button>
</div>
<div class="image">
<img src="secondimage.jpg" alt="Second">
<button class="remove">X</button>
</div>`;
setup();
document.getElementsByClassName("remove")[0].click();
console.log(document.body.innerHTML);
This is what I have. As soon as I run the program, it removes the first image without the user clicking on it. And I have no idea how to fix it.
function setup() {
var myImage = document.getElementsByClassName("image");
document.getElementsByClassName("remove")[0].
addEventListener("click", function(){
myImage[0].parentNode.removeChild(myImage[0]);});
}
// Example case.
document.body.innerHTML = `
<div class="image">
<img src="firstimage.jpg" alt="First">
<button class="remove">X</button>
</div>
<div class="image">
<img src="secondimage.jpg" alt="Second">
<button class="remove">X</button>
</div>`;
setup();
document.getElementsByClassName("remove")[0].click();
console.log(document.body.innerHTML);
The getElementsBy* methods return HTMLCollections, which can be difficult to work with. Consider using querySelectorAll instead, which returns a static NodeList - unlike an HTMLCollection, it can be iterated over directly, it won't change while it's being iterated over, and it's much more flexible.
You want to iterate over each element, which is a lot more elegant than assigning to each element in the collection individually, so try something like this instead:
document.querySelectorAll('.remove')
.forEach(button =>
button.addEventListener('click', () => button.parentElement.remove())
)
.remove removes an element from the DOM.
The reason why the first image is removed automatically before you even click on it is because of the document.getElementsByClassName("remove")[0].click(); which is directly under the setup() function call.
Which means as soon as the function is called to perform the task, document.getElementsByClassName("remove")[0].click(); is immediately performed and removes the first image using index 0 and click().
So to solve this, try removing that [0] index or remove document.getElementsByClassName("remove")[0].click(); which is not useful in your case, and see how it goes.
function setup() {
let myImage = document.querySelectorAll(".remove").forEach(function (button){
button.addEventListener('click', function(){
button.parentElement.remove()
})
});
}
// Example case.
document.body.innerHTML = `
<div class="image">
<img src="firstimage.jpg" alt="First">
<button class="remove">X</button>
</div>
<div class="image">
<img src="secondimage.jpg" alt="Second">
<button class="remove">X</button>
</div>`;
setup();
document.getElementsByClassName("remove").click();
console.log(document.body.innerHTML);
import React from 'react';
import {useState} from 'react';
const ImageGallery = ({links}) =>{
const [data,setData] = useState(links)
const removeElement = (removeElement) => {
const newsetdata = data.filter((index) => index !== removeElement);
setData(newsetdata);
console.log(newsetdata)
// setData(data.splice(index,1));
};
return (
<>
<div>
{
data.map((abc,i,data)=> {
return(
<div key={i}>
<img src={abc} alt="images"/>
<button onClick={() => removeElement(data[i])}>X
</button>
</div>
)
})
}
</div>
</>
)
}
export default ImageGallery;

Separate scope variablesin angular

I have one scope variables for four elements in div. When I change the variable it affects all the four elements within which it is included. I am beginner in angular js and can't handle it alone.
Here is an example to explain better:
JS:
/* controller-home.js ********************************************************/
app.controller("homeController", function($scope, $http, $state) {
$scope.heading = "SWITCHES";
$scope.button1 = "Хол"
$scope.button2 = "Кухня"
$scope.button3 = "Баня"
$scope.button4 = "Балкон"
$scope.imageSrc = "LitLamp.png";
$scope.onOf = function() {
console.log("Switched");
if ($scope.imageSrc === "LitLamp.png") {
$scope.imageSrc = "NotLit.png";
}
}
})
The HTML:
<div style="text-align: center;">
<h1 >SWITCHES</h1>
<div ng-controller="homeController">
<div style="display:inline-block;">
<button ng-click="onOf()" class="homeSwitchButton">{{button1}}</button>
<img class="homeButtonImage" src="{{imageSrc}}" alt="Lamp" >
</div>
<div style="display:inline-block;">
<button ng-click="onOf()" class="homeSwitchButton">{{button2}}</button>
<img class="homeButtonImage" src="{{imageSrc}}" alt="Lamp" >
</div>
<div style="display:inline-block;">
<button ng-click="onOf()" class="homeSwitchButton">{{button3}}</button>
<img class="homeButtonImage" src="{{imageSrc}}" alt="Lamp" >
</div>
<div style="display:inline-block;">
<button ng-click="onOf()" class="homeSwitchButton">{{button4}}</button>
<img class="homeButtonImage" src="{{imageSrc}}" alt="Lamp" >
</div>
</div>
</div>
The problem is that when I hit one of the four buttons, all the images change. How to group image with button, or when I hit the first button only the image below it to change and the rest three to remain unchanged?
The problem here is because you are using the same variable imageSrc for all image. What you can do here is create an object for each image.
$scope.images = {
button1: 'source.png',
button2: 'source.png',
button3: 'source.png',
button4: 'source.png'
}
In the onOf method you can pass the name of the button you are changing
$scope.onOf = function(buttonName) {
if ($scope.images[buttonName] === 'bla.png') {
$scope.images[buttonName] = 'yay.png';
}
}
And in the html you set the images calling each property and passing the name of the button as argument on onOf
<div style="display:inline-block;">
<button ng-click="onOf('button1')" class="homeSwitchButton">{{button1}}</button>
<img class="homeButtonImage" src="{{images.button1}}" alt="Lamp" >
</div>
Better approach: You can put the buttons as an array and use ng-repeat
$scope.buttons = [{ name: 'bla', image: 'yay.png'}]
$scope.onOf = function(button) {
if (button.image === 'yay') {
...
}
}
And in the html
<div ng-repeat="button in buttons" style="display:inline-block;">
<button ng-click="onOf(button)" class="homeSwitchButton">{{button.name}}</button>
<img class="homeButtonImage" src="{{button.image}}" alt="Lamp" >
</div>

Categories

Resources