how to carousel GIF in background using JavaScript? - javascript

I am having difficulty to carousal gif in body background using javascript. I have set background in css body and set a variable in root in style.css to access this variable in javascript. This way is not working. my javascript code is perfect but I unable to change url in style.css. Can anyone help me please? Thanks
var index=0;
var images = ['https://media.giphy.com/media/BHNfhgU63qrks/source.gif','https://media.giphy.com/media/l3q2LucQ5TmyO7dFS/source.gif','https://media.giphy.com/media/l0O9xcDNUrPMfYQAE/source.gif','https://media.giphy.com/media/xUOxeWFk7gEwF13wDS/source.gif','https://media.giphy.com/media/BTWsSlrSHGNTa/source.gif','https://media.giphy.com/media/3gWENmQ8qo896QNhPV/source.gif']; //get all the images and saved them into an array
var totalImages = images.length;
function slideImages(){
document.documentElement.style.setProperty('--bg-change-gif',url(images[index]));// get images by specific index
if(index<totalImages-1){
index++;
}
else
{
index=0;
}
setTimeout(slideImages,250)
}
window.onload = slideImages;
:root {
--bg-change-gif:url(https://media.giphy.com/media/EfcqFUzY6asdq/source.gif);
}
body {
font-family: 'Montserrat', sans-serif;
min-height: 100vh;
max-height: 100vh;
margin: 0;
color: #fff;
display: -webkit-box;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex-direction: column;
background: var(--bg-change-gif);
background-size: cover;
height: 100%;
overflow: hidden;
}

Your code has a bit of error here:
document.documentElement.style.setProperty('--bg-change-gif',url(images[index]));// get images by specific index
It will throw an error saying url is not defined. You should change it to this:
document.documentElement.style.setProperty('--bg-change-gif','url('+images[index]+')');// get images by specific index
Here is your updated snippet!
var index=0;
var images = ['https://media.giphy.com/media/BHNfhgU63qrks/source.gif','https://media.giphy.com/media/l3q2LucQ5TmyO7dFS/source.gif','https://media.giphy.com/media/l0O9xcDNUrPMfYQAE/source.gif','https://media.giphy.com/media/xUOxeWFk7gEwF13wDS/source.gif','https://media.giphy.com/media/BTWsSlrSHGNTa/source.gif','https://media.giphy.com/media/3gWENmQ8qo896QNhPV/source.gif']; //get all the images and saved them into an array
var totalImages = images.length;
function slideImages(){
document.documentElement.style.setProperty('--bg-change-gif','url('+images[index]+')');// get images by specific index
if(index<totalImages-1){
index++;
}
else
{
index=0;
}
setTimeout(slideImages,250)
}
window.onload = slideImages;
:root {
--bg-change-gif:url(https://media.giphy.com/media/EfcqFUzY6asdq/source.gif);
}
body {
font-family: 'Montserrat', sans-serif;
min-height: 100vh;
max-height: 100vh;
margin: 0;
color: #fff;
display: -webkit-box;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
flex-direction: column;
background: var(--bg-change-gif);
background-size: cover;
height: 100%;
overflow: hidden;
}

Related

Implementing animations on an array of string values

My goal is to try to animate text. Every example on how to animate text looks at a singular string. I'd like to animate an array of string values, one after the other.
The problem I'm getting is that although I'm creating the elements needed successfully, only the .word3 class is actually being rendered. I'm not sure why this is and after banging my head against the wall, I'm not sure how to fix it.
I've used a lot of stack overflow resources to overcome things like using setTimeout in a for loop which lead to using an iife.. Here is the code that I've settled on for the time being. Using async caused a lot of issues as async needs to be at the top level apparently and I often got the 'unexpected reserved keyword error'.
There must be a simple way to do this?
All help is appreciated, thanks!
const wrapper = document.querySelector(".wrapper");
const buttonCreate = document.querySelector(".create-element");
const buttonAnimate = document.querySelector(".animation");
buttonCreate.addEventListener("click", createElement);
let i = 0;
let j = 0;
let sampleArray = ["Just", "another", "cool", "heading"];
function createElement() {
// debugger
// Create text wrapper in main body and add class
const newDiv = document.createElement("div");
newDiv.classList.add("text-wrapper");
wrapper.insertAdjacentElement("afterbegin", newDiv);
// Modifying text-wrapper html to include p tag with dynamic class
function word() {
sampleArray.map((word, i) => {
newDiv.innerHTML += `<p class="word${i}"></p>`;
let element = document.querySelector(`.word${i}`);
console.log(element);
let j = 0
let interval = setInterval(() => {
element.innerText += word[j];
j++;
if(j === word.length) {
clearInterval(interval)
}
}, 200)
});
};
word();
return;
}
html {
box-sizing: border-box;
}
*,*::before, *::after {
box-sizing: inherit;
}
body {
margin: 0;
}
.wrapper {
width: 100%;
background-color: #333;
color: #FFA;
text-align: center;
height: 100vh;
display: flex;
flex-direction: row;
gap: 10rem;
align-items: center;
justify-content: center;
font-size: 4rem;
position: relative;
}
.text-wrapper {
position: absolute;
top: 0;
width: 100%;
display: flex;
gap: 3rem;
flex-direction: column;
justify-content: center;
justify-content: space-around;
}
.button {
font-size: 3rem;
border-radius: 6px;
background-color: #47cefa;
}
.button:hover {
cursor: pointer;
background-color: #BCEF4D;
}
<section class="wrapper">
<button class="button create-element">Create Element</button>
<button class="button animation">Start Animation</button>
</section>
Instead of setInterval in a loop of the array, just create a recursive function that calls setTimeout and calls itself and increments the array counter until the end of the array.
The lay out of my answer is off because I'm not exactly sure on what your expected layout is
const wrapper = document.querySelector(".text-wrapper");
const buttonAnimate = document.querySelector(".animation");
buttonAnimate.addEventListener("click", animation);
let i = 0;
let sampleArray = ["Just", "another", "cool", "heading"];
function animation() {
if (i < sampleArray.length) {
let el = document.createElement("p");
el.innerHTML = sampleArray[i];
wrapper.appendChild(el);
i++;
setTimeout(animation, 200);
}
}
.wrapper {
width: 100%;
background-color: #333;
color: #FFA;
text-align: center;
height: 100vh;
display: flex;
flex-direction: row;
gap: 10rem;
align-items: center;
justify-content: center;
font-size: 4rem;
position: relative;
}
.text-wrapper {
position: absolute;
top: 0;
width: 100%;
display: flex;
gap: 3rem;
flex-direction: column;
justify-content: center;
justify-content: space-around;
}
.button {
font-size: 3rem;
border-radius: 6px;
background-color: #47cefa;
}
.button:hover {
cursor: pointer;
background-color: #BCEF4D;
}
<section class="wrapper">
<button class="button animation">Start Animation</button>
<div class="text-wrapper"></div>
</section>

How to design the notification container in CSS?

I have a task - to make a notification display for some web-application.
The notifications appear in the bottom right corner of the window and disappear after some time.
Or the notifications can be gone by clicking on a notification item.
If there are multiple notifications, they should be stacked.
Each new notification moves the notification stack up.
If the stack of notifications grows larger than the height of the window, then the top older notifications must move to the next stack, which must be displayed to the left of the newer notification stack.
Similarly, if the second stack reaches the height of the window, then the oldest notifications should move to the third stack.
Schematically, it should look like this:
I was able to obtain the correct order of displaying notifications, but I can't get the notification container to be positioned against the right edge of the window.
function notify(msg) {
let element = document.createElement('div');
element.classList.add('notification');
element.innerHTML = msg;
let timeout;
element.onclick = () => element.remove();
element.onmouseenter = () => clearTimeout(timeout);
element.onmouseleave = () => createTimeout();
createTimeout();
let recentElement = container.firstElementChild;
if(recentElement) recentElement.before(element);
else container.appendChild(element);
indicator.innerHTML='Last msg is '+msg;
function createTimeout() {
timeout = setTimeout(() => {
element.remove()
}, 10000);
}
}
let notifyIndex = 0;
x1.onclick = () => {
notify(++notifyIndex);
}
x10.onclick = () => {
for (let i = 0; i < 10; i++)
notify(++notifyIndex);
};
x30.onclick = () => {
for (let i = 0; i < 30; i++)
notify(++notifyIndex);
};
body {
margin: 0;
min-height: 100vh;
display: grid;
place-items: center;
}
.action-list button {
width: 4rem;
margin .5rem
}
#container {
position: fixed;
display: flex;
flex-direction: column-reverse;
justify-content: flex-end;
flex-wrap: wrap-reverse;
align-content: flex-end;
align-items: flex-end;
bottom: 0;
right: 30px;
max-height: 100vh;
}
.notification {
transition: all 500ms ease-in-out;
box-shadow: 0 0 1rem #0004;
margin: 0 1rem 1rem 0;
background: #f9f99f;
color: #000;
border: 1px solid #0008;
padding: .2rem 1rem;
cursor: default;
user-select: none;
}
<div id="container"></div>
<div>
<div id="indicator">Last msg is 0</div>
<div class="action-list">
<button id="x1">x1</button>
<button id="x10">x10</button>
<button id="x30">x30</button>
</div>
</div>
I set an indentation of 30 pixels, so that you can see that the notifications go over the edge of the window.
The idea is that stacks of recent notifications should not go over the edge of the window.
What am I doing wrong?
position: fixed;
display: flex;
flex-direction: column-reverse;
justify-content: flex-end;
flex-wrap: wrap-reverse;
align-items: flex-end;
bottom: 0;
right: 30px;
max-height: 100vh;
Try this, let me know if it works!
Tldr: Your Align-content: flex-end was making it grow to the right

Send mouseover event to all overlaid elements [duplicate]

Is it possible to make two overlapping divs, both clickable?
I've appended divs to two containers, #container and #container2. Their styles are exactly the same only except one is flex-direction: column; and one is flex-direction: column;. Both position:absolute with #container2 on top. I made each of the appended child clickable to fill its background color. Only the div on top is clickable so far, is there a way to make both clickable? or is there another way to have the bottom div react to my clicks?
window.addEventListener('load', init);
function init() {
calculateGrid();
//calculate grid
function calculateGrid() {
var w = window.innerWidth;
var h = window.innerHeight;
var totalNum = Math.trunc(w / 25) * Math.trunc(h / 25);
function randomInRange(from, to) {
let x = Math.random() * (to - from);
return x + from;
};
for (var i = 0; i < totalNum; i++) {
var div = document.createElement('div');
div.setAttribute('class', 'grid');
div.style.width = randomInRange(3, 10) + 'vw';
div.style.height = randomInRange(5, 10) + 'vh';
document.getElementById('container').appendChild(div);
document.getElementById('container2').appendChild(div.cloneNode(true));
}
};
$(".grid").click(function() {
$(this).toggleClass('selected');
});
};
#container {
width: 100vw;
height: 95vh;
position: absolute;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
flex-direction: column;
overflow: hidden;
}
#container .grid {
border: 1px solid blue;
}
#container2 {
width: 100vw;
height: 95vh;
position: absolute;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
flex-direction: row;
overflow: hidden;
}
#container2 .grid {
border: 1px solid red;
}
.grid {
font-size: 10px;
color: white;
}
#container .selected {
background-color: blue;
}
#container2 .selected {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="wrapper">
<div id="container"></div>
<div id="container2"></div>
</div>
View on CodePen
One method is to use Document.elementsFromPoint() to return "an array of all elements at the specified coordinates". Iterate through that array, adding the "selected" class to "grid" elements.
window.addEventListener('load', init);
function init() {
// build grid
function calculateGrid() {
var w = window.innerWidth;
var h = window.innerHeight;
var totalNum = Math.trunc(w / 25) * Math.trunc(h / 25);
function randomInRange(from, to) {
let x = Math.random() * (to - from);
return x + from;
};
for (var i = 0; i < totalNum; i++) {
var div = document.createElement('div');
div.setAttribute('class', 'grid');
div.style.width = randomInRange(3, 10) + 'vw';
div.style.height = randomInRange(5, 10) + 'vh';
document.getElementById('container1').appendChild(div);
document.getElementById('container2').appendChild(div.cloneNode(true));
}
};
// handle grid clicks
function handleGridClick(e) {
let elms = document.elementsFromPoint(e.clientX, e.clientY);
Array.from(elms).forEach(elm => {
if (elm.classList.contains('grid'))
elm.classList.add('selected');
});
}
// initialize grid and click handler
calculateGrid();
document.addEventListener('click', handleGridClick);
};
.container {
width: 100vw;
height: 95vh;
position: absolute;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
overflow: hidden;
}
#container1 {
flex-direction: column;
}
#container1 .grid {
border: 1px solid blue;
}
#container1 .grid.selected {
background-color: blue;
}
#container2 .grid {
border: 1px solid red;
}
#container2 .grid.selected {
background-color: red;
}
<div id="wrapper">
<div id="container1" class="container"></div>
<div id="container2" class="container"></div>
</div>
You can't actually hover two items at the same time in plain 'ol HTML/CSS - for that you will need JavaScript as explained in the accepted solution. However, there's a CSS-only solution to allow hovering over the different layers, which was fun to figure out at the very least.
So the idea is that you have these invisible boxes on top of the visible ones. The invisible boxes only have borders such that any time your mouse hits a border, some clever z-index swapping takes place to make the visible containers change their stacking order.
For every .grid item you need to create a corresponding .box item: https://jsfiddle.net/ryanwheale/01v5yz86/93/

Sidebar with height 100vh doesn't fill page if other content on page causes scroll

I'm building a sidebar in React and I'm trying to set the height to fill the entire page even if other content on the page goes beyond the initial window size.
Right now it only goes to the bottom of the initial page height, and if content on the page-- next to the sidebar, not inside of it --overflows, the user can scroll and the content is visible, but the sidebar stops at the end of the initial page height.
Here is a screenshot of what I'm describing
I've tried the following:
min-height: 100vh;
height: 100vh;
---
min-height: 100vh;
height: 1px;
---
min-height: 100vh;
height: 100vh;
max-height: 500vh;
---
html, body {margin: 0; padding: 0;}
[Update] I've tried using all the different sizing I can think of and have seen online. % all the way from html to the container of the sidebar, vh all the way down, min-height all the way down, min-height & max-height all the way down, different browsers to see if it's chrome/firefox. I think the issue is a conceptual one with how sizing works in CSS but I don't know what questions to ask to find the answer.
To no avail. I've looked around for similar issues and haven't found any solutions that work for me.
I'm not a frontend guy so I'm not entirely sure why this isn't working.
Here is the stylesheet for the sidebar and its ancestors:
html {
font-size: 10px;
overflow-x: hidden;
margin:0;
padding: 0;
height: -webkit-fill-available;
}
body {
margin: 0;
padding: 0;
min-height: 100vh;
min-height: -webkit-fill-available;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: whitesmoke;
}
#root {
width: 100vw;
height: 100vh;
}
.container {
position: relative;
margin-left: 5%;
margin-right: 5%;
width: 90%;
color: rgb(58,58,58);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.Settings {
min-height: 100vh;
width: 100vw;
display: flex;
flex-direction: row;
}
.Settings-Sidebar {
display: flex;
overflow: visible;
flex-direction: column;
min-height: 100vh;
min-height: -webkit-fill-available;
width: 34%;
background: rgb(58,58,58);
color: white;
}
and the react component in case its relevant (wip):
const Settings = () => {
const user = useSelector(state => state.authReducer.user);
const loading = useSelector(state => state.loadingReducer.isLoading);
const location = useLocation();
const hash = location.hash;
const dispatch = useDispatch();
const [active, setActive] = useState(null);
useEffect(() => {
if (!active) {
const activeElement = document.querySelector('.Settings-Sidebar-Option.active');
setActive(activeElement);
}
dispatch(stopLoading());
if (hash.includes('#confirm-email')) {
const target = document.querySelector('#settings-confirm-option');
target.click();
}
}, [active, dispatch, hash]);
if (user.username === undefined) return <Redirect to="/" />
if (loading) {
return <Loading />
}
const setActiveSetting = (evt) => {
const target = evt.target
// Prevent changing active element to random whitespace
if (target.classList.contains('Settings-Sidebar-Option')) {
// remove the active class from all setting options
for (let sibling of target.parentElement.children) {
sibling.classList.remove('active');
}
target.classList.add('active');
setActive(target);
}
}
return (
<div className="Settings">
<div className="Settings-Sidebar">
<h1 className="Settings-Sidebar-Header">Settings</h1>
<div className="Settings-Sidebar-Content" onClick={setActiveSetting}>
<h2 className="Settings-Sidebar-Option active" id="settings-general-option">General</h2>
{!user.confirmed ? (
<h2 className="Settings-Sidebar-Option" id="settings-confirm-option">Verify Email</h2>
) : null}
<h2 className="Settings-Sidebar-Option" id="settings-contact-option">Contact</h2>
<h2 className="Settings-Sidebar-Option" id="settings-about-option">About</h2>
<h2 className="Settings-Sidebar-Option" id="settings-delete-option">Delete Account</h2>
</div>
</div>
<div className="Settings-Content">
{active ? <SettingsContent current={active.innerText} /> : null}
</div>
</div>
)
}
It's hard to tell how to fix the problem without any demo but I think you need to use position property of CSS to your sidebar container to get the desired result.
That's what I could tell for now from the image you've shared.
Let me know if you need more help.

Want to display tags with click event javascript

im new to javascript so if my code isn't the best i apologise in advance! Im trying to display the tags when a certain name is clicked with the click event (eventListener), but I have no idea how! I tried writing the code how I want it, but now im stuck. I want the tags to be displayed in the aside 1 if the name is clicked. Any help is appreciated!
window.addEventListener('load', init);
const cardsContainer = document.querySelector("#cards")
const birdNames = ["Koolmees", "Specht", "kerkuil"]
const birdImages = ["https://www.natuurpunt.be/sites/default/files/styles/content-wide/public/koolmees_fr_van_bauwel.jpg?itok=arfFjeTb&c=312068de040ea85bb4eb43164e28b3b2", "https://www.buitenleven.nl/wp-content/uploads/2019/10/grote-bonte-specht.jpg", "https://www.vogelhuisjes.nl/media/wysiwyg/vogels-in-de-tuin/vogels-in-nederland/xkerkuil.jpg.pagespeed.ic.8a2v4rM0Z3.jpg"]
const birds = [
{ name: "Koolmees", image: "https://www.natuurpunt.be/sites/default/files/styles/content-wide/public/koolmees_fr_van_bauwel.jpg?itok=arfFjeTb&c=312068de040ea85bb4eb43164e28b3b2", tag:"rotterdam, koolmees, kleine vogel" },
{ name: "specht", image: "https://www.buitenleven.nl/wp-content/uploads/2019/10/grote-bonte-specht.jpg" },
{ name: "kerkuil", image: "https://www.vogelhuisjes.nl/media/wysiwyg/vogels-in-de-tuin/vogels-in-nederland/xkerkuil.jpg.pagespeed.ic.8a2v4rM0Z3.jpg" }
]
const Birdtags = ["rotterdam, koolmees, kleine vogel", "specht, nijmegen, kleine vogel", "uil, eindhoven, grote vogel, roofvogel"]
let Field;
let target;
function init()
{
//Click handler for every card
Field = document.getElementById('field');
Field.addEventListener('click', playingFieldClickHandler);
//starting
addCard();
//Listen to input of chosen name by user
let playForm = document.getElementById('form');
playForm.addEventListener('submit', formSubmitHandler);
}
function addCard(birdImage, birdName){
const cardDiv = document.createElement("flex-item")
cardDiv.classList.add("card")
cardsContainer.appendChild(cardDiv)
const img = document.createElement("img")
img.src = birdImage
cardDiv.appendChild(img)
const nameDiv = document.createElement("div")
nameDiv.innerText = birdName
cardDiv.appendChild(nameDiv)
}
function playingFieldClickHandler(e)
{
/** what do I put here???*/
}
function formSubmitHandler(e)
{
//Prevent default form submit
e.preventDefault();
//If the value is the right one, you won!
if (birdNames === "koolmees") {
/** display tags */
} else if (birdNames === "specht") {
/** display tags */
}
else if (birdNames === "kerkuil") {
/** display tags */
}
}
function addCards(){
for(let i = 0; i<birdNames.length; i++){
addCard(birdImages[i], birdNames[i])
}
}
addCards()
flex-container {
/* We first create a flex layout context */
display: flex;
/* Then we define the flow direction
and if we allow the items to wrap
* Remember this is the same as:
* flex-direction: row;
* flex-wrap: wrap;
*/
flex-flow: row wrap;
/* Then we define how is distributed the remaining space */
justify-content: space-around;
padding: 0;
margin: 0;
list-style: none;
}
flex-item {
background: #ABEBC6;
padding: 5px;
width: 250px;
height: 200px;
margin-top: 10px;
line-height: 50px;
color: black;
font-weight: bold;
font-size: 3em;
text-align: center;
}
nav {
display: flex;
flex-flow: row wrap;
justify-content: flex-end;
list-style: none;
margin: 0;
background: #A2D9CE;
}
nav a {
text-decoration: none;
display: block;
padding: 1em;
color: white;
}
nav a:hover {
background: #1565C0;
}
wrapper {
display: flex;
flex-flow: row wrap;
font-weight: bold;
text-align: center;
}
wrapper > * {
padding: 10px;
flex: 1 100%;
}
header {
background: #DAF7A6;
}
footer {
background: #28B463;
}
main {
text-align: left;
background: #A2D9CE;
}
aside {
background: #28B463;
}
#media all and (min-width: 600px) {
.aside { flex: 1 0 0; }
}
#media all and (min-width: 800px) {
main { flex: 3 0px; }
aside { order: 1; }
main { order: 2; }
footer { order: 3; }
}
body {
width: 100%;
}
#media all and (max-width: 800px) {
nav {
justify-content: space-around;
}
}
#media all and (max-width: 600px) {
nav {
flex-flow: column wrap;
padding: 0;
}
nav a {
text-align: center;
padding: 10px;
border-top: 1px solid rgba(255, 255, 255,0.3);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
nav li:last-of-type a {
border-bottom: none;
}
}
p1 {
font-family: "Times New Roman", Times, serif;
font-size: 40px;
}
p2 {
font-family: Arial, Helvetica, sans-serif;
}
p3 {
font-family: "Lucida Console", "Courier New", monospace;
}
img {
width: 250px;
height: 150px;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="css/style2.css">
<title>Test week 2</title>
</head>
<body>
<wrapper>
<header><p1>Vogel magazine voor vogelspotters!</p1></header>
<main>
<flex-container id="cards">
</flex-container>
</main>
<aside>Aside 1</aside>
<footer>Footer</footer>
</wrapper>
<script src="js/DOM4.js"></script>
</body>
</html>
Admittedly I modified the HTML structure a little as there were errors with the markup, possibly screwed up your CSS and changed the multiple source arrays for a single Object literal but you should be able to adapt the following to suit your needs. I made this do what I thought you were trying to do.
window.addEventListener('load', init);
const cardsContainer = document.querySelector('#cards');
const aside = document.querySelector('#wrapper aside');
/*
If you re-structure your data into a single Object literal
you will, I think, find less issues with maintaining several
arrays and ensuring they all have the same number of items etc
This sort of data structure can easily be created in the form of
JSON data from a database query!
Each sub-object ( aka - Bird ) can be extended easily to have additional
properties quite easily, especially if database driven.
If you remove, from the img src, the `scheme` you can generally get the image to download
using the same scheme as the parent page. One day ALL websites will be hosted on SSL
so this will be redundant but in the meantime this might help prevent warnings
*/
const birds={
'Koolmees':{
src:'//www.natuurpunt.be/sites/default/files/styles/content-wide/public/koolmees_fr_van_bauwel.jpg',
tags:'rotterdam, koolmees, kleine vogel'
},
'Specht':{
src:'//www.buitenleven.nl/wp-content/uploads/2019/10/grote-bonte-specht.jpg',
tags:'specht, nijmegen, kleine vogel'
},
'kerkuil':{
src:'//www.vogelhuisjes.nl/media/wysiwyg/vogels-in-de-tuin/vogels-in-nederland/xkerkuil.jpg.pagespeed.ic.8a2v4rM0Z3.jpg',
tags:'uil, eindhoven, grote vogel, roofvogel'
}
};
/*
It is unclear from the code what you hope to do with the `submithandler`
especially given that there is no form ( or was no form ) so I guessed
that you were hoping to do something similar to what this method does..
if there is no `figcaption` below the image it will add the caption and
assign the `tags` text which is assigned to the image as a dataset attribute
*/
const clickhandler=function(e){
let fig=e.target.parentNode.querySelector('figcaption');
if( fig==null ){
fig=document.createElement('figcaption');
fig.textContent=this.dataset.tags
e.target.parentNode.appendChild( fig );
}else{
e.target.parentNode.removeChild(fig)
}
aside.textContent=fig==null ? '' : this.dataset.tags;
}
function init(){
/* the first does nothing, the 2nd has errors and the 3rd is incomplete...
//Click handler for every card
document.getElementById('field').addEventListener('click', playingFieldClickHandler);
//starting
//addCard(src,name,desc);
//Listen to input of chosen name by user
document.getElementById('form').addEventListener('submit', formSubmitHandler);
*/
document.getElementById('cards').querySelectorAll('.card').forEach( card => {
card.addEventListener('click',clickhandler );
});
}
function addCard(birdImage, birdName, birdTags){// now takes 3 arguments
let item = document.createElement('flex-item');
item.classList.add('card');
item.dataset.tags=birdTags; //assign the tags as a dataset atttribute
cardsContainer.appendChild(item)
let img = document.createElement('img')
img.src = birdImage;
img.title=birdTags; // tags also assigned for the img title
item.appendChild(img)
let name = document.createElement('div')
name.innerText = birdName
item.appendChild(name)
}
/**********************************************************
Unclear how these two functions are really to be used
- unchanged
*/
function playingFieldClickHandler(e)
{
/** what do I put here???*/
}
function formSubmitHandler(e)
{
//Prevent default form submit
e.preventDefault();
//If the value is the right one, you won!
if (birdNames === "koolmees") {
/** display tags */
} else if (birdNames === "specht") {
/** display tags */
}
else if (birdNames === "kerkuil") {
/** display tags */
}
}
/*
With the new data structure a new approach to iterating through the
data is required. Using the `object.keys` method allows us to quickly
iterate through each sub-object. The `key` is the bird name.
*/
function addCards(){
Object.keys( birds ).forEach( key => {
let bird=birds[ key ];
addCard( bird.src, key, bird.tags )
})
}
addCards()
body{
width:100%;
height:100vh;
margin:0;
padding:0;
box-sizing:border-box;
}
flex-container {
/* We first create a flex layout context */
display: flex;
/* Then we define the flow direction
* and if we allow the items to wrap
* Remember this is the same as:
* flex-direction: row;
* flex-wrap: wrap;
*/
flex-flow: row wrap;
flex:10;
margin:auto;
/* Then we define how is distributed the remaining space */
justify-content: space-around;
padding: 0;
list-style: none;
}
flex-container figcaption{
font-size:1rem;
line-height:1rem;
color:white;
}
flex-item {
background: #ABEBC6;
padding: 5px;
width: 250px;
min-height: 200px;
max-height:250px;
margin-top: 10px;
line-height: 50px;
color: black;
font-weight: bold;
font-size: 3em;
text-align: center;
cursor:pointer;
}
nav {
display: flex;
flex-flow: row wrap;
justify-content: flex-end;
list-style: none;
margin: 0;
background: #A2D9CE;
}
nav a {
text-decoration: none;
display: block;
padding: 1em;
color: white;
}
nav a:hover {
background: #1565C0;
}
#wrapper {
display: flex;
flex:10;
flex-direction:column;
font-weight: bold;
text-align: center;
min-height:100vh;
margin:auto;
padding:0;
}
#wrapper > * {
padding: 10px;
flex: 1 100%;
}
header {
background: #DAF7A6;
flex:2!important;
order:1;
display:flex;
align-items:center;
justify-content:center;
}
footer {
background: #28B463;
flex:1!important;
order:3;
display:flex;
align-items:center;
justify-content:center;
}
main {
text-align: left;
background: #A2D9CE;
flex:50!important;
order:2;
}
aside {
display:flex;
align-items:center;
justify-content:center;
background: #28B463;
flex:1;
margin:auto;
max-height:2rem;
width:100%;
padding:0!important;
}
#media all and (min-width: 600px) {
.aside { flex: 1 0 0; }
}
#media all and (min-width: 800px) {
main { flex: 3 0px; }
aside { order: 1; }
main { order: 2; }
footer { order: 3; }
}
#media all and (max-width: 800px) {
nav {
justify-content: space-around;
}
}
#media all and (max-width: 600px) {
nav {
flex-flow: column wrap;
padding: 0;
}
nav a {
text-align: center;
padding: 10px;
border-top: 1px solid rgba(255, 255, 255,0.3);
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
nav li:last-of-type a {
border-bottom: none;
}
}
p1 {
font-family: "Times New Roman", Times, serif;
font-size: 40px;
}
p2 {
font-family: Arial, Helvetica, sans-serif;
}
p3 {
font-family: "Lucida Console", "Courier New", monospace;
}
img {
width: 250px;
height: 150px;
}
<div id='wrapper'><!-- There is no HTML element `wrapper` -->
<header><p1>Vogel magazine voor vogelspotters!</p1></header>
<main>
<flex-container id="cards"></flex-container><!-- unusual to assign custom elements without accompanying javascript/css -->
</main>
<aside>Aside 1</aside>
<footer>Footer</footer>
</div>

Categories

Resources