Changing innerHTML - javascript

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.

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>

How to write a document.querySelector for the following code

I'm having difficulty writing the document.querySelector for the following code. Currently I've written this code as querySelector but it does not encompass everything...
Please help me improve this, thank you.
Edit: as there seemed to be some confusion, let me elaborate. I would like all the elements, from div, a, img, everything to be encompassed in the querySelector.
var areaa = document.querySelector("#menu #envelope #links");
<div id="menu">Click here to browse the internet.
<div id="envelope">
<div id="links" >
<div>
<a id="g" class="redirect">
<img id="google" src="assets/google.png" />
</a>
</div>
<div style="width: 20%;"></div>
<div>
<a id="s" class="redirect">
<img id="sava" src="assets/Logo_Sava.png"/>
</a>
</div>
</div>
</div>
</div>
Edit 2 - as more code was required (the href elements are removed / added as needed)...
var menu = document.getElementById("menu");
var areaa = document.querySelectorAll(".areaa");
menu.addEventListener("mouseenter", addHref);
//areaa.addEventListener("mouseleave", remHref);
document.addEventListener("mousemove", function(){
if(this != areaa){
remHref();
}
});
menu.addEventListener("click", addHref);
document.addEventListener("click", function (){
if (this != areaa){
remHref();
}
});
var g = document.getElementById("g");
var s = document.getElementById("s");
function remHref (){
if (g.hasAttribute("href")){
g.removeAttribute("href");
}
if (s.hasAttribute("href")){
s.removeAttribute("href");
}
}
function addHref (){
setTimeout(activate, 250);
}
function activate (){
document.getElementById("g").setAttribute("href", "https://www.google.com");
document.getElementById("s").setAttribute("href", "https://www.example.com");
}
you might want to add a class to all elements you want to be captured, then use document.querySelectorAll
var areaa = document.querySelectorAll(".my-class");
html shoud look like this:
<div id="menu" class="my-class">Click here to browse the internet.
<div id="envelope" class="my-class">
<div id="links" class="my-class">
<div>
<a id="g" class="redirect">
<img class="my-class" id="google" src="assets/google.png" />
</a>
</div>
<div style="width: 20%;"></div>
<div>
<a id="s" class="redirect">
<img id="sava" src="assets/Logo_Sava.png"/>
</a>
</div>
</div>
</div>
If you want to select everything you can use the below:
var areaa = document.querySelectorAll("#menu #envelope #links *");
If you want to be more specific you can do the following (the code below will select all of the anchor tags and images inside #links):
var areaa = document.querySelectorAll("#menu #envelope #links a, #menu #envelope #links img");
You can use querySelectorAll
The Document method querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.
Learn more: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
You can use it like this:
var areaa = document.querySelectorAll('*');
This will return all items.
You can replace document with the container if you want to restrict this to a specific div.
2 things, either add a class to every div
<div id="menu" class="area">Click here to browse the internet.
<div id="envelope" class="area">
<div id="links" class="area" >
<div>
<a id="g" class="redirect">
<img id="google" src="assets/google.png" />
</a>
</div>
<div style="width: 20%;"></div>
<div>
<a id="s" class="redirect">
<img id="sava" src="assets/Logo_Sava.png"/>
</a>
</div>
</div>
</div>
</div>
and select all divs by
let areaa = getElementsByClassName("area");
or you can use document.querySelectorAll("yourclassname") to access all divs of that class name

How to separate highlighted objects JavaScript

On my website I have 5 categories. In every category I have 1 image with a title and 1 description text. While hovering over the image the image and the text are highlighted in the same moment (by adding a class: "highligthCategory").
My problem is that every time I hover over any of 5 images, all 5 descriptions are highlighted. How could I limit the highlighting to the specific description related only to one image?
I assume the problem appears due to the fact that the second loop is inside the first loop, but because I have also event listeners I don't know how to separate them and make two loops work separately.
const category = document.querySelectorAll(".category");
const categoryText = document.querySelectorAll(".category-text");
const categoryArray = Array.prototype.slice.call(category);
const categoryTextArray = Array.prototype.slice.call(categoryText);
categoryArray.map(x => {
x.addEventListener ("mouseover", function(e) {
categoryTextArray.map(y =>
y.classList.add("highligthCategory"));
}, false);
x.addEventListener ("mouseout", function(e) {
categoryTextArray.map(y =>
y.classList.remove("highligthCategory"));
}, false);
});
HTML
<section id="service-1">
<div class="row">
<figure>
<img class="category" src="img/1.svg" alt="" data- type="feature">
</figure>
<h3>Service 1</h3>
<p class="category-text">Example of the text.</p>
</div>
</section>
The problem is that in the event listeners you're modifying all the .category-text elements instead of just those related to the element on which the event was triggered. You can do something like this to fix that:
const categories = document.querySelectorAll(".category");
categories.forEach(category => {
const description = category.closest('.row').querySelector('.category-text');
category.addEventListener("mouseover", () => {
description.classList.add("highligthCategory");
}, false);
category.addEventListener("mouseout", () => {
description.classList.remove("highligthCategory");
}, false);
});
.highligthCategory {
color: red;
}
<section id="service-1">
<div class="row">
<figure>
<img width="50" class="category" src="https://slm-assets0.secondlife.com/assets/696995/lightbox/a907d0cc6780bc3af5f83b8d1d54e1a3.jpg?1277109877" alt="" data- type="feature">
</figure>
<h3>Service 1</h3>
<p class="category-text">Example of the text.</p>
</div>
</section>
<section id="service-1">
<div class="row">
<figure>
<img width="50" class="category" src="https://slm-assets0.secondlife.com/assets/696995/lightbox/a907d0cc6780bc3af5f83b8d1d54e1a3.jpg?1277109877" alt="" data- type="feature">
</figure>
<h3>Service 1</h3>
<p class="category-text">Example of the text.</p>
</div>
</section>
In the above example, I'm creating a description variable which will hold a reference to the .category-text element related to the .category element in the current iteration and in the event listeners I'm modifying only this element's classList

Closing full screen JS menu on a one page website when menu links are clicked

I am having a play with a menu idea. I have very little JS knowlege so I want to know if what i am trying to achieve is doable.
I have been playing with a multibox menu from codrops this menu
From the looks of it the menu is designed to link to external pages, what I am trying to do is link to sections within the same page as I would look to build a one page site, so what I need is the menu to close when one of the menu links are clicked, as currently it just stays open.
I have tried to use the same "class" function from the close button in the links but this for some reason makes the close button disappear, not an effective solution.
I have looked at similar questions posted and tried to fix with previous answers but I'm having no luck.
<main>
<div class="frame">
<header class="codrops-header">
<div class="codrops-links">
<a class="codrops-icon codrops-icon--prev" href="https://tympanus.net/Development/GridLayoutScrollableContent/" title="Previous Demo"><svg class="icon icon--arrow"><use xlink:href="#icon-arrow"></use></svg></a>
<a class="codrops-icon codrops-icon--drop" href="https://tympanus.net/codrops/?p=36043" title="Back to the article"><svg class="icon icon--drop"><use xlink:href="#icon-drop"></use></svg></a>
</div>
<h1 class="codrops-header__title">Multibox Menu</h1>
</header>
<p class="info">12 — 24 May 2019 · Bannockburn · Stirling · UK</p>
<a class="github" href="https://github.com/codrops/MultiboxMenu/" title="Find this project on GitHub"><svg class="icon icon--github"><use xlink:href="#icon-github"></use></svg></a>
</div>
<div class="content">
<div class="background" style="background-image: url(img/1.jpg)"></div>
<h2 class="content__title">Carmeca</h2>
<p class="content__tagline">Europe's most immersive LARP experience</p>
</div>
<nav class="menu">
<div class="menu__item menu__item--1" data-direction="bt">
<div class="menu__item-inner">
<div class="mainmenu">
Story
Chronicles
Tour
Contact
</div>
<p class="label label--topleft label--vert-mirror">the important stuff</p>
<p class="label label--bottomright label--vert">made in bannockburn</p>
</div>
</div>
<div class="menu__item menu__item--2" data-direction="lr">
<div class="menu__item-inner">
<div class="menu__item-map"></div>
The location
</div>
</div>
<div class="menu__item menu__item--3" data-direction="bt">
<div class="menu__item-inner">
<div class="sidemenu">
<span class="sidemenu__item-inner">The Gameplay</span>
<span class="sidemenu__item-inner">About LARP</span>
<span class="sidemenu__item-inner">The Rules</span>
<span class="sidemenu__item-inner">History</span>
<span class="sidemenu__item-inner">People</span>
<span class="sidemenu__item-inner">Join</span>
<span class="sidemenu__item-inner">...</span>
</div>
</div>
</div>
<div class="menu__item menu__item--4" data-direction="rl">
<div class="menu__item-inner">
<p class="label label--topleft label--line">Join us now</p>
Learn how to <br> participate
</div>
</div>
<div class="menu__item menu__item--5" data-direction="tb">
<div class="menu__item-inner">
<p class="quote">Hail to thee, our infantry, still brave, beyond the grave</p>
</div>
</div>
<button class="action action--menu"><svg class="icon icon--menu"><use xlink:href="#icon-menu"></use></svg></button>
<button class="action action--close"><svg class="icon icon--close"><use xlink:href="#icon-close"></use></svg></button>
</nav>
</main>
{
// Class Menu.
class Menu {
constructor(el) {
this.DOM = {el: el};
// Open and close ctls.
this.DOM.openCtrl = this.DOM.el.querySelector('.action--menu');
this.DOM.closeCtrl = this.DOM.el.querySelector('.action--close');
this.DOM.openCtrl.addEventListener('click', () => this.open());
this.DOM.closeCtrl.addEventListener('click', () => this.close());
this.DOM.openCtrl.addEventListener('mouseenter', () => {
allowTilt = false;
tilt.reset()
});
this.DOM.openCtrl.addEventListener('mouseleave', () => {
allowTilt = true;
});
// The menu items.
this.DOM.items = Array.from(this.DOM.el.querySelectorAll('.menu__item'));
// The total number of items.
this.itemsTotal = this.DOM.items.length;
// Custom elements that will be animated.
this.DOM.mainLinks = this.DOM.el.querySelectorAll('.mainmenu > a.mainmenu__item');
this.DOM.sidemenuLinks = this.DOM.el.querySelectorAll('.sidemenu span.sidemenu__item-inner');
this.DOM.menulink = this.DOM.el.querySelector('.menu__item-link');
}
// Open the menu.
open() {
this.toggle('open');
}
// Close the menu.
close() {
this.toggle('close');
}
toggle(action) {
if ( this.isAnimating ) return;
// (dis)allow the main image tilt effect.
allowTilt = action === 'open' ? false : true;
this.isAnimating = true;
// Toggling the open state class.
this.DOM.el.classList[action === 'open' ? 'add' : 'remove']('menu--open');
// After all is animated..
const animationEnd = (pos) => {
if ( pos === this.itemsTotal-1 ) {
this.isAnimating = false;
}
};
I have tried to take this line of code and copy it from th JS file this.DOM.closeCtrl.addEventListener('click', () => this.close()); and change the closeCtrl and replace it with mainLinks however that didnt work and to be totally honest I have absolutely no idea what i'm doing.
I would imagine it's a fairly straightforward fix for someone that understands JS.
Hopefully you can help. Thanks
I found a solution, which i'm sure can be improved, but however it does the job...
HTML (add the item--close classes)
Item1
Item2
Item3
Item4
Item5
JAVASCRIPT (add this code demo.js)
// Open and close ctls.
this.DOM.openCtrl = this.DOM.el.querySelector('.action--menu');
this.DOM.closeCtrl = this.DOM.el.querySelector('.action--close');
this.DOM.ItemcloseCtrl1 = this.DOM.el.querySelector('.item--close1');
this.DOM.ItemcloseCtrl2 = this.DOM.el.querySelector('.item--close2');
this.DOM.ItemcloseCtrl3 = this.DOM.el.querySelector('.item--close3');
this.DOM.ItemcloseCtrl4 = this.DOM.el.querySelector('.item--close4');
this.DOM.ItemcloseCtrl5 = this.DOM.el.querySelector('.item--close5');
this.DOM.openCtrl.addEventListener('click', () => this.open());
this.DOM.closeCtrl.addEventListener('click', () => this.close());
this.DOM.ItemcloseCtrl1.addEventListener('click', () => this.close());
this.DOM.ItemcloseCtrl2.addEventListener('click', () => this.close());
this.DOM.ItemcloseCtrl3.addEventListener('click', () => this.close());
this.DOM.ItemcloseCtrl4.addEventListener('click', () => this.close());
this.DOM.ItemcloseCtrl5.addEventListener('click', () => this.close());

jQuery Newbie, need a little help

Okay, so I am in the process of recreating this feature:
http://www.w3.org/html/logo/#the-technology
I current have it so when you click on a link, it will add a class to the image that relates to that link (href="#one" on the <a> and then id="#one" on the <img>), however it is currently not going through each <a> tag and only one. And also it is not removing the class I requested.
Code follows:
JS
$(document).ready(function() {
var container = '#portfolio #text_container';
var img_container = '#portfolio #image_container';
$(container).children('a').bind('click', function() {
var this_attr = $(this).attr('href');
var this_img = $(img_container).find('img').attr('id');
if(this_attr == this_img) {
//$(img_container).find('img').hasClass('current').removeClass('current');
// ^^^ This line isn't working, any ideas? :/
$(img_container + ' img[id*="' + this_attr + '"]').addClass('current');
}
else {
alert(this_img + ' this img');
alert(this_attr + ' this attr');
}
});
});
And the HTML is as follows
<div id="portfolio">
<div id="image_container">
<img src="http://static.jquery.com/files/rocker/images/logo_jquery_215x53.gif" alt="" class="current" id="#one" />
<img src="http://static.jquery.com/files/rocker/images/btn_downloadLarge.gif" alt="" id="#two" />
</div>
<div id="text_container">
Item 1
Item 2
<p id="#one" class="current">A bunch of text!</p>
<p id="#two">The second bunch of text!</p>
</div>
</div>
Please let me know if you need any more information :)
rcravens fixed this with the following code..
JS
$(document).ready(function() {
$('#text_container a').click(function(evt) {
evt.preventDefault();
$('.current').removeClass('current');
var href = $(this).attr('href');
$("." + href).addClass('current');
});
And the HTML..
<div id="portfolio">
<div id="image_container">
<img src="http://static.jquery.com/files/rocker/images/logo_jquery_215x53.gif" alt="" class="one current" />
<img src="http://static.jquery.com/files/rocker/images/btn_downloadLarge.gif" alt="" class="two" />
</div>
<div id="text_container">
Item 1
Item 2
<p class="one current">A bunch of text!</p>
<p class="two">The second bunch of text!</p>
</div>
</div>
My interpretation of what you are trying to do is here:
http://jsfiddle.net/rcravens/wMhEC/
The code is changed a bit. You shouldn't have multiple elements with the same id.
Bob
The reason this isn't working:
if(this_attr == this_img)
is because this_attr is a URL and this_img is an ID attribute value.

Categories

Resources