I'm experiencing a JavaScript error on a pen on codepen.io.
TypeError: window.CP is undefined
I tried to look it up and understood that it's connected to an infinite loop protection, but I can't find a way to solve the problem.
Here is the link to the pen on CodePen (where it doesn't work) and to a JSFiddle (where it works).
Here is the code on the snippet (where it also works).
(The green block is supposed to change color when you scroll)
<script>
function scrollFunction() {
var content = document.getElementById('content').querySelectorAll('p')
var contentY = []
for (i = 0; i < content.length; i++) {
contentY[i] = content[i].offsetTop
}
var html = document.documentElement
var y = html.scrollTop
var windowY = window.innerHeight
var phone = document.getElementById('phone')
for (i = 0; i < content.length; i++) {
if (y > contentY[i] - windowY * 0.4) {
phone.classList.add('color' + (i + 1))
phone.classList.remove('color' + i)
} else {
phone.classList.remove('color' + (i + 1))
}
}
}
window.onscroll = function () {
scrollFunction()
}
</script>
body {
background: white;
color: #323232;
font-weight: 300;
height: 100vh;
margin: 0;
font-family: Helvetica neue, roboto;
}
nav {
position: fixed;
top: 0;
left: 0;
width: 100%;
background: white;
-webkit-box-shadow: 0px -6px 25px 20px rgba(0, 0, 0, 0.44);
-moz-box-shadow: 0px -6px 25px 20px rgba(0, 0, 0, 0.44);
box-shadow: 0px -6px 25px 20px rgba(0, 0, 0, 0.44);
}
nav ul {
list-style: none;
display: flex;
flex-wrap: wrap;
}
nav ul li {
padding: 0 1rem;
}
main {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
#content {
width: 50%;
}
/* The first paragraph has a margin-top = the size of the screen*/
#content p:first-child {
margin-top: 100vh;
}
#content p {
margin: 0;
margin-bottom: 100vh;
}
/* Same margin-top as the 1st paragraph + sticky at 40% from the top*/
#phone {
margin-top: 100vh;
width: 8rem;
height: 13rem;
max-height: 70vh;
position: sticky;
top: 40%;
background: lightgreen;
transition: background 0.2s;
}
#phone.color1 {
background: palevioletred;
}
#phone.color2 {
background: purple;
}
#phone.color3 {
background: royalblue;
}
#phone.color4 {
background: rgb(30, 150, 104);
}
<nav class="menu">
<ul>
<li>Menu</li>
<li>Bar</li>
<li>Scrolling</li>
<li>Effect</li>
</ul>
</nav>
<main>
<div id="content" class="content">
<p>
One advanced diverted domestic sex repeated bringing you old. Possible procured her trifling laughter thoughts property she met way.
</p>
<p>
Finished her are its honoured drawings nor. Pretty see mutual thrown all not edward ten. Particular an boisterous up he reasonably frequently.
</p>
<p>
May musical arrival beloved luckily adapted him. Shyness mention married son she his started now. Rose if as past near were. To graceful he elegance oh moderate attended entrance pleasur
</p>
<p>
Out believe has request not how comfort evident. Up delight cousins we feeling minutes.
</p>
</div>
<div id="phone">
</div>
</main
CodePen has a problem with the normal loops but working well with Array methods like: forEach, map, or reduce.
Chrome console output:
Uncaught TypeError: Cannot read property ‘shouldStopExecution’ of undefined
In order to solve it, I had to change the normal loop with forEach instead. Example
Related
So I want to have a specific scrolling section on my website, where while you scroll the wheel down (or drag the scrollbar down), the content scrolls sideways while the scrollbar on the right of the screen also moves down.
I googles like a ton yesterday for examples or packages, but didn´t find what I need - actually kind of. The best thing I found was this codepen:
https://codepen.io/alvarotrigo/pen/VwWMjVp
<div class="vertical-section">
Content above
</div>
<div class="sticky-container">
<main>
<section>
<h1>Beep</h1>
</section>
<section>
<h1>Boop</h1>
</section>
<section>
<h1>Boooom</h1>
</section>
<section>
<h1>The End</h1>
</section>
</main>
</div>
<div class="vertical-section">
Content Below
</div>
<div class="sticky-container">
<main>
<section>
<h1>Beep</h1>
</section>
<section>
<h1>Boop</h1>
</section>
<section>
<h1>Boooom</h1>
</section>
<section>
<h1>The End</h1>
</section>
</main>
</div>
-----------------------
<a href="https://alvarotrigo.com/blog/scroll-horizontally-with-mouse-wheel-vanilla-java/" target="_blank" class="read-article">
Read the article 👉
</a>
html,
body {
margin: 0;
font-family: sans-serif;
}
.vertical-section{
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
main {
overflow-x: hidden;
display: flex;
position: sticky;
top:0;
}
h1 {
margin: 0;
padding: 0;
}
section {
min-width: 50vw;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
font-size: 4ch;
}
section:nth-child(even) {
background-color: teal;
color: white;
}
.read-article{
position: absolute;
top: 10px;
left: 10px;
z-index: 999;
color: #000;
background: white;
padding: 10px 20px;
border-radius: 10px;
font-family: arial;
text-decoration: none;
box-shadow: rgb(50 50 93 / 25%) 0 0 100px -20px, rgb(0 0 0 / 30%) 0 0 60px -15px;
}
.read-article:hover{
background: #d5d5d5;
box-shadow: rgb(50 50 93 / 25%) 0 0 100px -20px, rgb(0 0 0 / 30%) 0 0 60px 0px;
}
iframe[sandbox] .read-article{
display: none;
}
/**
* By Alvaro Trigo
* Follow me on Twitter: https://twitter.com/imac2
*/
(function(){
init();
var g_containerInViewport;
function init(){
setStickyContainersSize();
bindEvents();
}
function bindEvents(){
window.addEventListener("wheel", wheelHandler);
}
function setStickyContainersSize(){
document.querySelectorAll('.sticky-container').forEach(function(container){
const stikyContainerHeight = container.querySelector('main').scrollWidth;
container.setAttribute('style', 'height: ' + stikyContainerHeight + 'px');
});
}
function isElementInViewport (el) {
const rect = el.getBoundingClientRect();
return rect.top <= 0 && rect.bottom > document.documentElement.clientHeight;
}
function wheelHandler(evt){
const containerInViewPort = Array.from(document.querySelectorAll('.sticky-container')).filter(function(container){
return isElementInViewport(container);
})[0];
if(!containerInViewPort){
return;
}
var isPlaceHolderBelowTop = containerInViewPort.offsetTop < document.documentElement.scrollTop;
var isPlaceHolderBelowBottom = containerInViewPort.offsetTop + containerInViewPort.offsetHeight > document.documentElement.scrollTop;
let g_canScrollHorizontally = isPlaceHolderBelowTop && isPlaceHolderBelowBottom;
if(g_canScrollHorizontally){
containerInViewPort.querySelector('main').scrollLeft += evt.deltaY;
}
}
})();
This is pretty much exactly what I was looking for but I wonder:
If there isn´t a more intuitive package that does exactly this?
If this is really that "clean"
but mostly the problem here is, because there is an eventlistener on the window only for the mousewheel, which means when not scrolling down via the mouse wheel, but with the scrollbar at the right, it won´t work.
Do you have any more ideas, what you could use or is this actually as good as it can get?
Thanks!
I'm new to coding, and I'm trying to learn the basics. I wanted to practice what I learned by making flashcards (nothing complicated like saving it, importing it, or exporting it). So far, I made a table that the user can edit. I know how to gather data from the table, but I don't know how to make a CSS flashcard appear every time the user adds a card to the table. I am aware that the code will not work since I put the CSS in JavaScript since this code is just meant to show what I am trying to do. Also, if I am taking a completely wrong approach, please let me know. Thank you! Please excuse the poor variable naming, I was just testing some things.
<script>
function getFlashcardValue() {
for (var repeat = 0; repeat < 200; repeat++) {
var Table = document.getElementById('flashcardsTable');
var column1 = 0;
var column2 = 1;
var numberOfFlashcards = 2;
for (var row = 0; row < numberOfFlashcards; row++) {
var Cells = Table.rows.item(1).cells;
var Question1 = Cells.item(column1).innerHTML;
var Cells1 = Table.rows.item(1).cells;
var Answer1 = Cells.item(column2).innerHTML;
document.getElementById("myFlashcardQuestion" + row).innerHTML = Question1;
document.getElementById("myFlashcardAnswer" + row).innerHTML = Answer1;
<div class="flip-card">
<div class="flip-card-inner">
<div class="flip-card-front">
<span id="myFlashcardQuestion1"></span>
</div>
<div class="flip-card-back">
<span id="myFlashcardAnswer1"></span>
</div>
</div>
</div>
}
}
}
</script>
<p style = "font-size: 25px">Hover over the flashcard to flip it!</p>
<style>
.flip-card {
background-color: transparent;
width: 350px;
height: 175px;
margin: auto;
padding: 5px 5px;
perspective: 1000px;
}
.flip-card-inner {
position: relative;
background-color: lightblue;
width: 100%;
height: 100%;
text-align: center;
transition: transform 0.6s;
transform-style: preserve-3d;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
}
.flip-card:hover .flip-card-inner {
transform: rotateY(180deg);
}
.flip-card-front, .flip-card-back {
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.flip-card-front {
background-color: lightblue;
width: 350px;
height: 175px;
color: black;
font-size: 35px;
text-alignment: center;
}
.flip-card-back {
background-color: red;
color: white;
font-size: 35px;
text-alignment: center;
transform: rotateY(180deg);
}
</style>
So first of all you can create a code snippet in stackoverflows editor (see below), or use jsfiddle and post a shared-link.
It depends on which action the user has to do after he enters the data.
If it is, for example, a button click, then it is possible to call a function that shows the user's input in the flashcard. Now if you want that for every single Q&A you have to create Elements in the for loop and edit them there. Here a little example.
var allCards = document.getElementById("allCards");
for (var i = 1; i <= 5; i++) { //i used 5, you should use length of data
var question = document.createElement("div");
question.textContent = "Question " + i;
question.classList.add("flip-card");
allCards.appendChild(question);
}
.flip-card {
background-color: lightblue;
width: 350px;
height: 175px;
margin: 10px auto;
padding: 5px 5px;
font-size: 35px;
text-align: center;
}
<div id="allCards"></div>
Edit:
As promised, here is an example of how you can set up the flip cards.
https://jsfiddle.net/ybu59hfp/1/
Your concern should now be resolved. If you have any further questions, feel free to write to me in the chat or read a little about JavaScript on the Internet.
I am trying to replicate the same behavior as in this
codepen in IE 11 (does not have css sticky)
I am able to detect when the item is offscreen at the start with:
if (
$(".main-content").height() + $(".main-content").offset().top <
$(".main-footer").offset().top
)
but then after it reaches the end of the scroll (in this case the page), I did not manage to check when it goes offscreen again. It is probably something simple as subtracting the scroll to figure out if the element is offscreen, I am just stuck...
Here is a codepen where I stuck am now.
IE doesn't support <main> so you can't use this tag in IE 11. You can monitor the scroll bar changes through JavaScript, and then change its class according to the position of the element.
Here is the code you can refer to:
$(document).scroll(function() {
var scroH = $(document).scrollTop();
var viewH = $(window).height();
var contentH = $(document).height();
$('.main-footer').addClass('main-footer1')
if (scroH > 100) {}
if (contentH - (scroH + viewH) <= 100) { // The height from the bottom is less than 100px
}
if (contentH <= (scroH + viewH + 100)) {
$('.main-footer').removeClass('main-footer1')
$('.main-footer').addClass('main-footer2')
} else {
$('.main-footer').addClass('main-footer1')
$('.main-footer').removeClass('main-footer2')
}
});
body {
color: #fff;
font-family: arial;
font-weight: bold;
font-size: 40px;
}
.main-container {
max-width: 600px;
margin: 0 auto;
border: solid 10px green;
padding: 10px;
margin-top: 40px;
}
.main-container * {
padding: 10px;
background: #aaa;
border: dashed 5px #000;
}
.main-container *+* {
margin-top: 20px;
}
.main-header {
height: 50px;
background: #aaa;
}
.main-content {
min-height: 1000px;
}
.main-footer {
border-color: red;
}
.main-footer1 {
position: fixed;
bottom: 0px;
margin: 0 auto;
width: 570px;
}
.main-footer2 {
position: relative;
margin-top: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="main-container">
<header class="main-header">HEADER</header>
<div class="main-content">MAIN contentH</div>
<footer class="main-footer">footer</footer>
</div>
Result in IE 11:
I am trying to show how much a user has scrolled through the page a with progress bar and I have done it. But I have a little confusion here.
Here is the code that I found to calculate scrollPercent which works well
windowHeight = Math.max(
html.clientHeight,
html.scrollHeight,
html.offsetHeight,
body.scrollHeight,
body.offsetHeight
);
const scrolledPercent =
((html.scrollTop || body.scrollTop) / (windowHeight - html.clientHeight)) *
100;
Initially, I thought, to get the scrollPercent , I need to get the current scrollPosition and divide that number with the total height of the page and multiply by 100% . which is like normally how we get % of something.
const scrolledPercent =
((html.scrollTop || body.scrollTop) / windowHeight) * 100;
but this line doesnot worked as I expected . If I do this the progress bar wont reach 100% even if I scroll to end of the page. I don't understand why am I wrong here !
So, my question is why do we need to decrease the html.clientHeight from windowHeight ?
Thank you.
Demo here:
// --------------------------------------------
// variables
// --------------------------------------------
const html = document.documentElement,
body = document.body,
countryList = document.querySelector(".country__list");
scrollNavigated = document.querySelector(".scroll__navigated");
let windowHeight;
// --------------------------------------------
// function
// --------------------------------------------
async function prepareListOfCountries() {
let list = await fetch("https://restcountries.eu/rest/v2/all");
list = Array.from(await list.json());
let markup = list
.map((country, index) => {
return `<li class="country__item card">
<span class="country__name">${country.name}</span
><span class="country__capital">${country.capital}</span>
<a href="javascript:;" class="country__flag">
<img src= '${country.flag}'> </a>
</li>`;
})
.slice(0, 30)
.join(" ");
countryList.innerHTML = markup;
}
function updateScrolledStatus(e) {
windowHeight = Math.max(
html.clientHeight,
html.scrollHeight,
html.offsetHeight,
body.scrollHeight,
body.offsetHeight
);
const scrolledPercent =
((html.scrollTop || body.scrollTop) / (windowHeight - html.clientHeight)) *
100;
// const scrolledPercent =
// ((html.scrollTop || body.scrollTop) / windowHeight) * 100; // this line doesnot work
scrollNavigated.style.width = scrolledPercent + "%";
}
prepareListOfCountries();
// --------------------------------------------
// event-handler
// --------------------------------------------
window.addEventListener("scroll", updateScrolledStatus);
*::after,
*::before,
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #fff;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
}
.container {
max-width: 980px;
margin: 0 auto;
}
.justify-between {
display: flex;
align-items: center;
justify-content: space-between;
}
.items-center {
display: flex;
align-items: center;
}
.card {
background-color: #fff;
box-shadow: 0 0 12px 12px rgba(0, 0, 0, 0.054);
border-radius: 4px;
padding: 16px;
}
.country__flag img {
height: 100%;
width: 100%;
}
.header {
padding: 24px 0;
background-color: #333;
color: #f1f1f1;
position: -webkit-sticky;
position: sticky;
}
.content {
padding: 50px 0;
}
.content__form {
margin: 0 auto;
margin-bottom: 32px;
}
.content__search {
width: 50%;
padding: 12px 16px;
border-radius: 20px;
border: 1px solid #ddd;
transition: 0.2s;
}
.content__search:hover {
box-shadow: 0 1px 6px 0 rgba(32, 33, 36, 0.28);
}
.content__search:focus {
outline: none;
}
.country__list {
margin-top: 50px;
margin: 10px auto;
}
.country__item {
display: flex;
justify-content: space-between;
margin-bottom: 16px;
}
.country__name, .country__capital, .country__flag {
width: 33.33%;
}
.country__flag {
width: 32px;
height: 24px;
}
.scroll__navigator {
height: 2px;
margin: 0 auto 32px;
background-color: #333;
position: -webkit-sticky;
position: sticky;
top: 0;
}
.scroll__navigated {
display: block;
height: 100%;
width: 0;
background: orangered;
transition: 0.3s linear;
}
<body>
<header class="header">
<div class="container">
All countries list
</div>
</header>
<main class="content">
<div class="container">
<form class="content__form">
<input class="content__search" />
</form>
<div class="scroll__navigator">
<span class="scroll__navigated"></span>
</div>
<section class="country">
<ul class="country__list">
<li class="country__item card">
<span class="country__name">Nepal</span
><span class="country__capital">Kathmandu</span>
</li>
</ul>
</section>
</div>
</main>
</body>
As an example, say that the height of your client is 100px and the height of your whole page is 500px.
When the scroll position is 0px, you're able to see the first 100px of your site, so from 0px to 100px.
At scroll position 100px, you can see the range 100px to 200px, because you've moved the page, and therefore the visible range, on by 100px.
At scroll position 400px, you can therefore see the range 400px to 500px – in other words, you've scrolled to the bottom.
This demonstrates that the scrollable height of the page (400px) is less than the actual height of the page (500px), namely by the height of the client.
To get the percentage scrolled, you need to use the scrollable height, so it is necessary to subtract the height of the client from the height of the page to get a correct value, or you'll never be able to scroll to the bottom. It's not possible to scroll by 500px on a site that is only 500px long!
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I have several list elements on my page that are created dynamically, and my goal now is to access all the <li> on my page using getElementsByTagName, but when I try to do it, console tells me that the length of my li array is 0.
I've read documentation and examples on getElementsByTagName use cases but didn't track the problem.
Here is my code:
window.addEventListener('DOMContentLoaded', function() {
let btn = document.querySelector('.sw-btn');
let content = document.querySelector('.content');
let filmsList = document.createElement('ul');
function getFilms() {
axios.get('https://swapi.co/api/films/').then(res => {
content.appendChild(filmsList);
for (var i = 0; i < res.data.results.length; i++) {
res.data.results.sort(function(a, b) {
let dateA = new Date(a.release_date),
dateB = new Date(b.release_date);
return dateA - dateB;
});
(function updateFilms() {
let addFilm = document.createElement('li');
filmsList.appendChild(addFilm);
let addFilmAnchor = document.createElement('a');
let addFilmId = document.createElement('p');
let addFilmCrawl = document.createElement('p');
let addFilmDirector = document.createElement('p');
let addFilmDate = document.createElement('p');
addFilmAnchor.textContent = res.data.results[i].title;
addFilmId.textContent = `Episode ID: ${res.data.results[i].episode_id}`;
addFilmCrawl.textContent = `Episode description: ${res.data.results[i].opening_crawl}`;
addFilmDirector.textContent = `Episode director: ${res.data.results[i].director}`;
addFilmDate.textContent = `Episode release date: ${res.data.results[i].release_date}`;
addFilm.append(addFilmAnchor, addFilmId, addFilmCrawl, addFilmDirector, addFilmDate);
})();
}
}).catch(err => {
console.log("An error occured");
})
let links = document.getElementsByTagName('li');
console.log(links.length);
};
btn.addEventListener('click', getFilms);
});
body {
max-height: 100vh;
padding: 0;
margin: 0;
font-family: Muli;
}
body::before {
background: url('https://upload.wikimedia.org/wikipedia/commons/thumb/6/6c/Star_Wars_Logo.svg/1200px-Star_Wars_Logo.svg.png') no-repeat center / cover;
background-size: cover;
content: "";
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -2;
opacity: 0.1;
}
h1 {
text-align: center;
color: #660d41;
font-size: 3em;
margin-top: 10px;
letter-spacing: 1px;
}
main {
display: flex;
align-items: center;
flex-direction: column;
}
.content {
max-width: 55%;
overflow-y: scroll;
max-height: 75vh;
}
ul {
list-style-type: none;
padding: 10px 20px;
}
li {
border-bottom: 1px solid orangered;
margin-bottom: 30px;
}
li:last-child {
border-bottom: none;
margin-bottom: 0;
}
a {
font-size: 1.7em;
color: #b907d9;
cursor: pointer;
margin-bottom: 10px;
}
p {
font-size: 1.2rem;
color: #0f063f;
margin: 10px 0;
}
button {
padding: .5em 1.5em;
border: none;
color: white;
transition: all 0.2s ease-in;
background: #da2417;
border-radius: 20px;
font-size: 1em;
cursor: pointer;
margin-top: 15px;
}
button:focus {
outline: none;
}
button:hover {
background: #e7736b;
}
button:active {
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.7) inset;
}
<link href="https://fonts.googleapis.com/css?family=Muli&display=swap" rel="stylesheet">
<h1>Star wars films</h1>
<main>
<div class="content"></div>
<button class="sw-btn">Find Films</button>
</main>
Here is the link on working pen. Thank you for your help.
So what's happening here is a classic mistake caused by an async ajax request. You are requesting data and then inserting elements based on that data. Then afterwards, you want to count elements.
The problem is though, that axios.get returns a Promise that will not immediately resolve, because a HTTP request is being made to another server. That obviously takes some time, hence the then method of the Promise interface.
What you want to do is move your counting code at the end of the .then() method, so that the elements are counted after they have been inserted.
tl;dr you are trying to count elements that simply aren't there at the time of the counting.
That's because length is outside of then.
That means you are logging length of empty html collection at the first rendering of the page.
put it inside of then and then it will show correct value
like this:
addFilm.append(addFilmAnchor, addFilmId, addFilmCrawl, addFilmDirector, addFilmDate);
let links = document.getElementsByTagName('li');
console.log(links.length);