So I am having trouble understanding how to do this and how to approach this issue... I have a scroll animation on my page and I want to hide that div with animation after 3 seconds when it comes into view.
My HTML code for animated element is:
<div class="scroll-animation-wrapper">
<div class="scroll-animation">
<span></span>
<span></span>
<span></span>
</div>
</div>
Code in my Typescript is:
hideAnimatedDiv() {
const animatedDiv = document.getElementsByClassName('scroll-animation');
this.animatedDiv = true;
setTimeout(() => {
console.log('hide');
this.animatedDiv = false;
}, 3000);
}
I keep getting this error:
ERROR in src/app/configurator/configurator.component.ts(577,14): error TS2339: Property 'animatedDiv' does not exist on type 'ConfiguratorComponent'.
src/app/configurator/configurator.component.ts(580,18): error TS2339: Property 'animatedDiv' does not exist on type 'ConfiguratorComponent'.
Your code is trying to find animatedDiv property as global, because you have used this.animatedDiv instead try like this.
HTML
<div class="scroll-animation-wrapper">
<div id="scroll-animation" class="scroll-animation">
<span>a</span>
<span>b</span>
<span>c</span>
</div>
</div>
TS
ngOnInit() {
this.hideAnimatedDiv()
}
hideAnimatedDiv() {
let animatedDiv = document.getElementById('scroll-animation');
animatedDiv.style.display = 'block';
setTimeout(() => {
console.log('hide');
animatedDiv.style.display = 'none';
}, 3000);
}
To hide any element, we need to use style.display property of that element, like shown in the code.
Note: I have used ngOnInit function to make sure that div is hidden after component load only.
If you want to hide div I would suggest you this:
<div class="scroll-animation-wrapper">
<div class="scroll-animation" *ngIf="isDisplayed">
<span></span>
<span></span>
<span></span>
</div>
</div>
As you can see I added " *ngIf="isDisplayed" ". You should add the property "isDisplayed" to the component.
public isDisplayed: boolean = true;
hideAnimatedDiv() {
setTimeout(() => {
this.isDisplayed = false;
}, 3000);
}
If you want to add animation in Angular, the best way is to implement it as Angular Team suggests:
With this specific case I would use ":enter" ":leave" approach: https://angular.io/guide/transition-and-triggers#use-of-ngif-and-ngfor-with-enter-and-leave
Related
I have these elements on my page:
<div id="123test"><p>test</p></div>
<div id="123test"><p>othertext</p></div>
And I am trying to remove the div if it contains "test" text inside, using Java Script, but it does not seem to work.
Here is my JS:
var container = document.getElementById('123test');
if (container.textContent=='test') {
container.style.display="none";
};
var container = document.getElementById('123test');
if (container.textContent == 'test') {
container.style.display = "none";
};
<div id="123test"><p>test</p></div>
<div id="123test"><p>othertext</p></div>
I also tried using :contains selector way, but the result was the same. The style of the container does not change at all. What do I do wrong? Is there another approach possible? This code is a simplified version of my project, but neither of these two work. I would be very gratefull if someone would help me to overcome the issue.
Make sure your HTML looks exactly like this:
<div id="123test"><p>test</p></div>
<!-- no whitespace or line breaks before or after <p>test</p> -->
and not like this
<div id="123test">
<p>test</p>
</div>
To avoid this problem, call trim() on container.textContent:
var container = document.getElementById('123test');
if (container.textContent.trim() == 'test') {
container.style.display = "none";
};
<div id="123test">
<p>test</p>
</div>
<div id="123test2">
<p>othertext</p>
</div>
And I am trying to remove the div if it contains "test" text inside, using Java Script [...]
If it is sufficient that test is contained, check for includes('test') instead:
var container = document.getElementById('123test');
if (container.textContent.includes('test')) {
container.style.display = "none";
};
<div id="123test">
<p>test123</p>
</div>
<div id="123test2">
<p>othertext</p>
</div>
Important sidenote: You cannot have more than one element with the same id.
Sidenote 2: :contains only exists in jQuery, not in CSS.
Sidenote 3 about using innerText: This had been my first approach, but for some strange reason on Safari/MacOS it won't hide the container:
var container = document.getElementById('123test');
if (container.innerText == 'test') {
container.style.display = "none";
};
console.log(container.innerText.length); // 6 (!) on Safari/MacOS
<div id="123test">
<p>test</p>
</div>
<div id="123test2">
<p>othertext</p>
</div>
Here is an example of checking an arbitrary DOM tree for text nodes that contain the string "test" and then hiding them by setting display: none;.
The function hideTestNodes accepts NodeList and primarily makes use of nodeType and textContent.
const wrapper = document.getElementById('wrapper')
const hideTestNodes = (children) => {
for (const child of children) {
if (child.nodeType === 1) {
// If the node is another Element, check its child nodes
hideTestNodes(child.childNodes)
}
// If the node is a text node and the content includes 'test'
// then hide the parent element containing the text node
if (child.nodeType === 3 && /test/i.test(child.textContent)) {
child.parentElement.style.display = 'none'
}
}
}
hideTestNodes(wrapper.childNodes)
<div id="wrapper">
<div>
<p>test</p>
</div>
<div>
<p>some other text</p>
</div>
<div>
<p>some deeply <span> nested test</span> text</p>
</div>
<div>
<p>this <span>includes</span> test.</p>
</div>
</div>
If you want to do that to only one specific div, then it's very simple:
NOTE: I added two seconds to let you see how it happens. you can remove the timer.
let test1 = document.getElementById("test1");
if (test1.innerHTML.includes("test")) {
setTimeout(() => {
test1.style.display = "none";
}, 2000);
}
<div id="container">
<div id="test1"><p>test</p></div>
<div id="test2"><p>othertext</p></div>
</div>
If you want to check all divs, it's still simple and you just need to make an array from them then use forEach loop to check all divs in that container:
let divs = document.getElementById("container").children;
[...divs].forEach(div => {
if (div.textContent.includes("test")) {
setTimeout(() => {
div.style.display = "none";
}, 2000);
}
});
<div id="container">
<div id="test1"><p>test</p></div>
<div id="test2"><p>othertext</p></div>
</div>
I am coding a blog with Nuxt.js, and I am connected with the API of ButterCMS.
I want to get the date (text) of the post, and slice it. My problem is that it return an error : TypeError: null is not an object (evaluating 'document.querySelector(".date").textContent'). When I execute the same code in the JS Console, it is working. I already tried to add a event listener to the load of the page, but it didn't change anything. Here is my code :
document.querySelector(".date").textContent.slice(0, 29);
<template>
<div id="blog-home">
<div class="recent-article-feed">
<div v-for="(post, index) in posts" :key="post.slug + '_' + index">
<router-link :to="'/blog/' + post.slug">
<div class="article">
<div class="dark-window">
<div class="text-box">
<h2 class="title">{{ post.title }}</h2>
<div>
<span class="author">
<i class="fa-solid fa-user"></i> Par Maxime Hamou
</span>
∙
<span class="date">
<i class="fa-solid fa-calendar-days"></i>
{{ post.published }}
</span>
</div>
<p class="description">
{{ post.summary }}
</p>
<p class="read">Lire l'article →</p>
</div>
</div>
</div>
</router-link>
</div>
</div>
</div>
</template>
<style>
#import url("../css/index.css");
#import url("../css/components/recent-article-feed.css");
</style>
<script>
import { butter } from "~/plugins/buttercms";
export default {
data() {
return {
posts: [],
};
},
methods: {
getPosts() {
butter.post
.list({
page: 1,
page_size: 10,
})
.then((res) => {
// console.log(res.data)
this.posts = res.data.data;
});
},
},
created() {
this.getPosts();
},
};
</script>
The first thing is to make sure we understand what the error is trying to tell us.
TypeError: null is not an object (evaluating 'document.querySelector(".date").textContent')
Generally when you see something (like a variable or element) being labeled as null or undefined that means it does not exist. This could be due to a timing issue (being called before it is created/ready) or due to a scope issue (like a variable being called outside of its declared scope/function).
Because you are using an API and template-based code, it is almost certainly a timing issue. You did mention you tried adding an event listener to the page load, however this only works if your element/data is set before the page load, which almost certainly does not happen.
Realistically, the page will always complete its load event first, and then data from the API will be returned. And after all of this, then your template-based code will plug in the data to your page. This can be assumed because your template-based code is using promises (indicated by the .then() method).
So how do you fix this? You have to wait for the element you need to actually exists. The best way I found to do this is with something like a MutationObserver. You can create a function that uses a Mutation Observer on the page and whenever the content of the page changes, it fires some code. Here you can check to see if your date element exists or not. When it does finally exists, this function can return a promise, which allows you to now finally execute some code (like getting the textContent of said element).
So try adding something like this:
// This declares the function to wait for an element to exist
const _ElementAwait = el => {
return new Promise(resolve => {
if(document.querySelector(el)) return resolve(document.querySelector(el));
const observer = new MutationObserver(ml => {
if(document.querySelector(el)) {
resolve(document.querySelector(el));
observer.disconnect();
}
});
observer.observe(document.body, { childList: true, subtree: true });
});
}
// Here we call the function to wait for an element with the class 'date'
_ElementAwait(".date").then(el => {
// Once it does exist, the element is returned and we can get the textContent
el.textContent.slice(0, 29);
});
I just added a setTimeout and it work. Thank you for your help. Here is my new code :
setTimeout(function(){
const date = document.querySelector(".date").textContent.slice(0, 29);
document.querySelector(".date").textContent = "";
document.querySelector(".date").textContent = date;
}, 1000);
EDIT :
I remplaced the setTimeout by butter.page.retrieve directly in the page where I want to execute the script (found in ButterCMS docs). When the page "simple-page" is retrieved, the code that add my script is executed. Here the new code :
butter.page.retrieve("*", "simple-page").then(() => {
const createScript = document.createElement("script");
createScript.src = "../script/post-informations.js";
document.head.appendChild(createScript);
});
as I said in title I have problem with HTML elements created with Element.insertAdjacentHTML() method, I'm trying about an hour to solve this but can't. I have button that create new HTML elements, couple of that elements is new buttons with same class or id, it's no matter, that I need to catch in some variable and than again use for event listener, for some reason the class or id for these new created button doesn't exist, is there any way to catch it and use it later, I need Vanila Javascript?
There is over 500 lines of code, this is only for mentioned method
btnClaim.addEventListener("click", () => {
rewardCurrent.style.display = "none";
claimedRewards.push(currentReward);
rewardsList.innerHTML = ``;
claimedRewards.forEach(function (rew, i) {
const html = `
<div class="reward" id="${i}">
<div class="img-text-cont">
<img src="${rew.imgUrl}" alt="">
<div class="text-cont">
<p class="claimed-reward-title">${rew.title}</p>
<p class="claimed-reward-price">$${rew.price}</p>
</div>
</div>
<div class="claimed-rewards-action">
<button id="btn-sell2">Sell</button>
<button id="btn-ship">Ship</button>
</div>
</div>
`;
rewardsList.insertAdjacentHTML("afterbegin", html);
I need that btn-sell2 and btn-ship buttons in variables.
your element is going to be created and doesn't exist at the time page loads, so js addeventlistener will throw an error. to solve you have 2 ways.
1- use parent node that element will be created inside.
addevenlistener to parent and use
parent.addeventlistener( event, function (event){
if(event.target.classList.contains("childClass") {}
}
2- give addeventlistener when creating the element :
function createElement () {
const elem = -craete elemnt-
elem.addeventlistener(event, function);
}
So I have a parent component, that hosts 2 sibling components.
something like this
<div *ngif="somecode()">
<sibling1>
</sibling1>
</div>
<div *ngif="somecode()">
<sibling1 [dataParams]=sibling1object.somedata>
</sibling1>
</div>
so I get the error that sibling1object.somedata is undefined but when I remove ngIf() from 1st div, the error disappears.
It doesn't matter if *ngIf resolves to true or false. so i get the error even when sibling1 successfully loads.
Use [hidden]="!somecode()" instead of *ngIf="somecode()"
Please add following code in parent.component.ts
public siblingOneLoaded: boolean = false;
ngOnDestroy(): void {
if (sibling1object.somedata) {
this.siblingOneLoaded = true;
}
}
Add following code to html file
<div *ngIf="siblingOneLoaded">
<sibling1 [dataParams]=sibling1object.somedata>
</sibling1>
</div>
I want to make a Javascript function where it reads the class of the selected element and adds the class active. How can I get the class of the HTML element where my function is?
I tried to make an Javascript function with document.getElementsByClassName(class), but that doesn't work.
function menuicon(){
var className = $('div').attr('class');
className.$(className).addClass("active");
}
<section class="menubar">
<div class="menuicon" onclick="classAdd()">
<span></span>
<span></span>
<span></span>
</div>
</section>
<section class="home">
<button class="hbutton" onclick="classAdd()"></button>
</section>
I want that the Javascript function reads out the class of the HTML element where the function is placed in.
You need to pass the element to the function:
onclick="classAdd(this)"
Then in the function, you just use .addClass, you don't need to use className.
function classAdd(element) {
$(element).addClass("active");
}
This code snippet only include 'active' in the classList of the div
var classAdd = function() {
var menuIcon = document.querySelector('div.menuicon');
menuIcon.addEventListener('click',() => {
menuIcon.classList.add('active');
});
}
If encase you want to stick with the div and the menuicon class.
Below code will work fine for you.
function classAdd() {
$("div.menuicon").attr("class", "menuicon active");
}