Adding div container with class name and html content with JavaScript - 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>

Related

Interchnage the children of two divs using a button

My document structure is:
<div id="mainWindow">
<div id="subele1"></div>
</div>
<div id="subWindow">
<div id="subele2"></div>
</div>
I want to create a button so that the children subele1 and subele2 are interchanged every time the button is clicked.
UPD
function handleButtonClicked() {
const mainElement = document.getElementById('subele1')
const subElement = document.getElementById('subele2')
const mainElementValue = mainElement.innerHTML
mainElement.innerHTML = subElement.innerHTML
subElement.innerHTML = mainElementValue
}
<div id="mainWindow">
<div id="subele1">main Window!</div>
</div>
<div id="subWindow">
<div id="subele2">sub Window?</div>
</div>
<button id='main' onclick={handleButtonClicked()}>switch</button>

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.

UI not being updated by the result of fetch

I am trying to load search results based on what the user typed (responsive search), I thought it was my event as I wanted it more responsive e.g keyup but it didn't work. Here is working codepen
and following in my code. I had been struggling for hours now. What am I doing wrong?
function generateHTML(el,toggleClass){
const div = document.createElement("div");
const card = div.classList.add("card","col-sm-6", "col-md-6", "col-lg-3", "m-2",toggleClass);
div.innerHTML = `
<a href='#' class="products">
<img src="${el.image}" class="card-img-top rounded" alt="${el.title}">
<div class="card-body">
<h5 class="card-title">${(slicer(el.title))}</h5>
</div>
</a>
`
grid.appendChild(div);
}
This should do what you actually want
//getting the reference to elements
const row = document.querySelector("#search");
const grid = document.querySelector("#grid");
document.addEventListener("DOMContentLoaded", function () {
const div = document.createElement("div");
const formGroup = div.classList.add("form-group");
div.innerHTML = `
<div class="alert alert-primary">
<label for="searchField">Search</label>
<input type="text" class="form-control" id="searchField" placeholder="Type in what your looking for">
</div>
`;
row.appendChild(div);
//fetchData()
//get the reference to form
var input = '';
const myInput = document.getElementById("searchField");
myInput.addEventListener("keyup", function (e) {
input = myInput.value;
console.log(input);
fetch('https://fakestoreapi.com/products/')
//convert the response to JSON
.then(res => res.json())
//use the data to filter if it matches or display all
.then(data => {
grid.innerHTML = '';
data.forEach(el => {
if (el.title.toLowerCase().includes(input.toLowerCase())) {
console.log('h')
generateHTML(el, "block")
}
})
})
});
//get the reference to input
//const input = form.searchField.value.trim();
//add a event to listen on key up
})
function generateHTML(el, toggleClass) {
const div = document.createElement("div");
const card = div.classList.add("card", "col-sm-6", "col-md-6", "col-lg-3", "m-2", toggleClass);
div.innerHTML = `
<a href='#' class="products">
<img src="${el.image}" class="card-img-top rounded" alt="${el.title}" width="100" height="auto">
<div class="card-body">
<h5 class="card-title">${(slicer(el.title))}</h5>
</div>
</a>
`;
grid.appendChild(div);
}
function slicer(str) {
return str.slice(0, 10);
}
<div class="container">
<div class="" id="search">
</div>
<div class="row" id="grid">
</div>
</div>

Remove parent element using ES6

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>

Combine two collections of elements with mobify.js

everyone.
I've just started using the mobifyjs toolkit and I've ran into a problem of combining two collections of elements into one.
On a page I'm trying to mobify there are two sets of links: with text and images. The HTML looks like the following:
<!-- links with text -->
<div id="products">
Product 1
Product 2
</div>
...
<!-- somewhere else on the page -->
<div id="productImages">
<img src="Product1.png />
<img src="Product2.png />
</div>
It needs to turn into the following:
<div class="items">
<div class="item">
<div class="img">
<img src="Product1.png />
</div>
<div class="title">
Product 1
</div>
</div>
<div class="item">
<div class="img">
<img src="Product2.png />
</div>
<div class="title">
Product 2
</div>
</div>
</div>
My current solution is to use map function, so in the mobify.konf I have something like the following:
'content': function(context) {
return context.choose(
{{
'templateName': 'products',
'products': function(){
return $('#productImages a').map(function() {
var href = $(this).attr('href') || '';
var div = $('<div class="item"><div class="img"></div><div class="title"></div></div>');
div.find('.img').append($(this).clone());
div.find('.title').append($('#products a[href="' + href + '"]').clone());
return div;
});
}
})
}
And the template is:
<div class="items">
{#content.products}
{.}
{/content.products}
</div>
This code does work but the approach itself is pretty ugly since I have to move a piece of markup code from the tmpl file into mobify.konf. Can anyone suggest a better solution?
The best way to do this sort of thing is to collect the relevant properties for your items (e.g. the product name, the image url and the link href) into a data structure in javascript, and then create a template for your new html structure in the .tmpl file. Something like
'products': function() {
var products = [],
$productLinks = $('#products a'),
$productImages = $('#productImages img')
len = $productNames.legnth;
for(var i = 0; i<len; i++) {
var $link = $productLinks.eq(i);
var $img = $productImages.eq(i);
products.push({name: $link.text(), href: $link.attr('href'), imgSrc: $img.attr('src')});
}
return products;
}
and then template it by iterating over the array items and inserting them into relevant places in the markup:
<div class="items">
{#content.products}
<div class="item">
<div class="img"><img src="{.imgSrc}" /></div>
<div class="title">{.name}</div>
</div>
{content.products}
</div>

Categories

Resources