Div not overflowing in a Chat - javascript

I'm trying to create a chat, but after some number of messages the new message doesn't appear in screen and i want to overflow, to user scroll down the messages, but just a few messages appears and after that number nothing happens, just appears the previous messages in a static way, i'm using React and Socket.io.
Code:
const [messagesAndAuthors, setMessagesAndAuthors] = useState<any>([]);
useEffect(() => {
socket.on('receivedMessage', (newMessage:{}) => {
messagesAndAuthors([...messagesAndAuthors, newMessage])
});
})
function sendingMessages(e : FormEvent) {
e.preventDefault();
if(message.trim()) {
const messageObject = {
userName,
message,
roomId
};
socket.emit('sendMessage', messageObject);
}
setMessage('');
}
----------------------------BACK-END(SOCKET.IO):
socketInfo.on('sendMessage', (data:any) => {
socketInfo.broadcast.emit('receivedMessage', data);
});
.chat-container {
margin: 0.5rem;
display: flex;
flex-direction: column;
align-items: center;
font: 400 1rem 'Sulphur Point';
background-color: #254441;
padding: 2rem 0;
border-radius: 2rem;
justify-content: space-between;
text-align: center;
max-height: 77.5vh;
overflow: auto;
}
.chat-container h1 {
background-color: #ff6f59;
padding: 0.2rem 4rem;
border-radius: 2rem;
text-align: center;
align-items: center;
justify-content: center;
margin-bottom: 1rem;
}
.messages-container {
text-align: start;
background-color: #254441;
border-radius: 2rem;
height: 90%;
margin-bottom: 0.5rem;
overflow: auto;
}
.messages-mine-style {
width: 15rem;
border: transparent;
border-radius: 1.5rem;
margin-top: 2rem;
text-decoration: none;
text-align: start;
list-style: none;
font: 700 1.4rem 'Sulphur Point';
padding: 0.2rem 0.6rem;
margin: 1rem 0;
}
.messages-mine-style li{
margin-left: 1rem;
}
.messages-mine-style li+li {
font: 400 1.4rem 'Sulphur Point';
}
.chat-container input {
background-color: #ff6f59;
padding: 1rem 4rem;
border-radius: 2rem;
text-align: center;
font: 700 1.2rem 'Sulphur Point';
outline: none;
border: transparent;
}
.chat-container input::placeholder {
color: #254441;
}
<form onSubmit={sendingMessages} className="chat-container">
<h1>Chat</h1>
<div className="messages-container">
{messagesAndAuthors.map((messageWithTheAuthor:any) => {
return (
<>
<ul className="messages-mine-style">
<li key={messageWithTheAuthor.author}>{messageWithTheAuthor.author}: </li>
<li>{messageWithTheAuthor.message}</li>
</ul>
</>
)
})}
</div>
<input value={message} onChange={(e) => {setMessage(e.target.value)}} type="text" placeholder="Digite sua mensagem"/>
</form>

Here's an example. You'll need to modify it to make it work for you, but it should serve as a good starting point.
function updateScroll() {
let el = document.getElementsByClassName("chat")[0];
let offset = el.scrollHeight - el.scrollTop;
if (offset < 120) el.scrollTop = el.scrollHeight;
}
var messageNumber = 1;
function addMessage() {
let msg = "<li class=\"chat-message\">new message "+ messageNumber++ +"</li>";
document.getElementsByClassName("chat-messages")[0].innerHTML += (msg);
updateScroll();
}
setInterval(addMessage, 2000);
addMessage();
.chat {
width: 250px;
height: 100px;
overflow: auto;
background-color: darkgray;
border: solid black 1px;
border-radius: 2px;
}
.chat-message {
list-style-type: none;
}
.chat-messages {
padding: 0px;
padding-left: 5px;
margin: 0px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="chat">
<ul class="chat-messages">
</ul>
</div>
This example only scrolls down if the user has scrolled down. If the user has scrolled up (to read previous messages, for example), then it will not scroll down.

Related

Get substring from url and copy to clip board?

Hey i am trying some thing for my school project, i hope you can help me in it.
I want to copy the substring from url, like
Url = https://www.example.com/blah/blah&code=12432
substring = 12432
Also i want to print the substring in Copy Box .
Please Help Me with this issue. It is required for my project to copy some text from string.
(function() {
var copyButton = document.querySelector('.copy button');
var copyInput = document.querySelector('.copy input');
copyButton.addEventListener('click', function(e) {
e.preventDefault();
var text = copyInput.select();
document.execCommand('copy');
});
copyInput.addEventListener('click', function() {
this.select();
});
})();
html, body {
height: 100%;
}
body {
font-size: 16px;
background: #FFD1DD;
display: flex;
align-items: center;
justify-content: center;
}
* {
box-sizing: border-box;
}
.wrapper {
padding: 0 5px;
}
h1 {
text-align: center;
font-size: 40px;
margin-bottom: 1.2em;
text-decoration: underline;
text-transform: uppercase;
}
p {
font-family: 'VT323', monospace;
font-size: 20px;
}
.container {
display: flex;
background: #FFA3BB;
border-radius: 7px;
padding: 10px;
margin: 0 auto;
}
h3 {
font-size: 28px;
text-transform: uppercase;
text-align: center;
span {
display: inline-block;
position: relative;
}
}
.copy, .paste {
flex-grow: 1;
width: 50%;
}
.copy {
border-right: 2px solid;
padding-right: 10px;
h3 {
span {
background: #76ECFF;
}
}
input {
padding-right: 90px;
}
}
.paste {
padding-left: 10px;
h3 {
span {
background: #FAE916;
}
}
}
form {
position: relative;
width: 100%;
input {
display: block;
width: 100%;
border: 3px solid;
outline: 0;
background: #FFF;
font-size: 25px;
padding: 5px 4px;
margin-bottom: 20px;
}
button {
display: block;
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
border: 0;
outline: 0;
color: #FFF;
background: #000;
font-family: 'VT323', monospace;
font-size: 25px;
text-transform: uppercase;
padding: 0.08em 0.8em;
cursor: pointer;
}
}
<div class="wrapper">
<h1>Link Copy</h1>
<p>Select the link text by clicking within the input then copy yourself or just click the copy button. Paste into the paste side to see that it works!</p>
<div class="container">
<div class="copy">
<h3>Copy <span><i class="fa fa-hand-peace-o"></i></span></h3>
<form>
<input type="text" value="https://codepen.io/she_codes/pen/OgrJJe/">
<button type="button">Copy</button>
</form>
</div>
<div class="paste">
<h3>Paste <span><i class="fa fa-smile-o"></i></span></h3>
<form>
<input type="text">
</form>
</div>
</div><!-- end .container -->
</div><!-- end .wrapper -->
Use this it will work
const params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop),
});
// Get the value of "some_key" in eg "https://example.com/?some_key=some_value"
let value = params.some_key; // "some_value"
try this, assuming nothing is ever after "code="
var url = window.location.href;
var index = url.indexOf("code=");
var substring = url.substring(index + 5);
copyInput.setAttribute('value', substring);

Insert HTML element

I am trying to insert an HTML element (in my file it is called "baseketTotal"). This element is something like a checkout form that has the total price and etc... The thing is that I am trying to put it only on the last movie in the list which I add to the bag.
In this link, it is a picture of how it looks now. So I need to display it only on the last movie, no matter if the list has 1,2, or 10 movies. Only on the last one.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD#48,400,0,0"
/>
<link rel="stylesheet" href="style.css" />
<title>Filmovizija</title>
</head>
<body>
<h1>Filmovizija</h1>
<div class="prozor"></div>
<h2>Shooping bag</h2>
<div class="shooping-cart"></div>
<script src="script.js"></script>
</body>
</html>
css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #22254b;
font-family: "Poppins", sans-serif;
}
h1 {
text-align: center;
color: #eee;
font-family: inherit;
margin-top: 30px;
margin-bottom: 30px;
}
.prozor {
display: flex;
flex-wrap: wrap;
}
.movie {
width: 300px;
border-radius: 4px;
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.3);
background-color: #373b69;
margin: 25px;
}
.movie-info {
color: #eee;
display: flex;
justify-content: space-between;
padding: 10px;
letter-spacing: 1px;
align-items: center;
}
.movie img {
width: 100%;
border-bottom: 1px solid white;
height: 450px;
}
.movie-info h3 {
font-weight: 300;
margin: 0;
}
.movie-info span {
font-weight: 400;
border-radius: 3px;
background-color: #22254b;
padding: 3px 7px;
}
.movie .kupi {
color: #eee;
display: flex;
justify-content: space-between;
padding: 10px;
padding-bottom: 15px;
letter-spacing: 1px;
align-items: center;
}
.movie .kupi button {
padding: 2px 8px;
font-size: 14px;
font-weight: 500;
}
.movie .kupi span {
font-size: 18px;
font-weight: 500;
}
/* ----------------------------------- SHOOPING CART ------------------------------------------------ */
.shooping-cart {
border-top: 2px solid rgb(214, 214, 214);
width: 1000px;
height: 500px;
margin-left: 25px;
}
h2 {
color: whitesmoke;
text-transform: uppercase;
font-size: 20px;
font-weight: 300;
margin-bottom: 20px;
margin-left: 25px;
}
.shooping-cart .single-item {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px;
border-bottom: 2px dotted grey;
}
.shooping-cart .single-item span {
background-color: rgb(255, 255, 255);
margin-left: 20px;
border-radius: 50%;
color: black;
}
.smallPic {
height: 70px;
width: 70px;
border: 1px solid grey;
}
.shooping-cart .single-item .opis {
align-items: center;
display: flex;
flex-direction: column;
color: white;
font-family: inherit;
}
.shooping-cart .single-item .opis h2 {
font-weight: 300;
margin-bottom: 5px;
}
.shooping-cart .single-item .opis h3 {
font-size: 14px;
font-weight: bold;
color: antiquewhite;
text-transform: uppercase;
}
.shooping-cart .single-item .kolicina input {
width: 30px;
text-align: center;
}
.shooping-cart .single-item .kolicina button {
padding: 2px 6px;
background-color: whitesmoke;
border: 0;
}
.single-total {
color: white;
margin-right: 20px;
}
/* ----------------------------------- SHOOPING CART TOTAL ALL ------------------------------------------------ */
.totalKosara {
float: right;
display: flex;
flex-direction: column;
width: 350px;
height: 160px;
margin-top: 15px;
}
.potvrdi {
display: flex;
width: 100%;
margin: 20px 0;
justify-content: space-between;
text-align: center;
}
.potvrdi .sub,
.price {
color: #eee;
font-weight: bold;
padding: 5px;
}
.text {
color: white;
font-size: 14px;
text-align: center;
}
.blue {
width: 100%;
align-items: center;
display: flex;
justify-content: center;
margin-top: 30px;
}
.blue button {
width: 100%;
border-radius: 2px;
border: 0;
padding: 10px;
background-color: #0b1050;
color: #eee;
font-family: inherit;
border: 1px solid grey;
}
scriptJS
const options = {
method: "GET",
headers: {
"X-RapidAPI-Key": "cd782e9b03mshbd50bac036f1802p16179djsn48c38f33f263",
"X-RapidAPI-Host": "online-movie-database.p.rapidapi.com",
},
};
const main = document.querySelector(`.prozor`);
const shoopingCart = document.querySelector(`.shooping-cart`);
const checkoutBtn = document.querySelector(`.checkoutBtn`);
fetch(
"https://online-movie-database.p.rapidapi.com/auto-complete?q=hacker",
options
)
.then((response) => response.json())
.then((data) => {
const list = data.d;
list.map((item) => {
const name = item.l;
const rank = item.rank;
const price = Math.floor(rank / 100);
const poster = item.i.imageUrl;
const movie = ` <div class="movie">
<img src=${poster} alt="${name}" />
<div class="movie-info">
<h3>${name}</h3>
<span>#${rank}</span>
</div>
<div class="kupi">
<button class="addToBag">Kupi film</button>
<span>${price} HRK</span>
</div>
</div>`;
main.innerHTML += movie;
//---------------------------------- add to basket --------------------------//
const button = document.querySelectorAll(`.addToBag`);
button.forEach((button) => {
button.addEventListener(`click`, function (e) {
const clicked = e.target;
const kupi = clicked.closest(`.kupi`);
const cijena2 = kupi.querySelector(`span`).innerText;
const cijena = cijena2.split(` `)[0];
const parent = kupi.closest(`.movie`);
const imeFilma = parent.querySelector(`.movie-info h3`).innerText;
const imgSrc = parent.querySelector(`img`).src;
const singleItem = `
<div class="single-item">
<span class="material-symbols-outlined deleteItem"> close </span>
<img src=${imgSrc} alt="aaa" class="smallPic" />
<div class="opis">
<h2>${imeFilma}</h2>
</div>
<div class="kolicina">
<button class="plus">+</button>
<input type="text" value="1" max="3" min="1" class="input"/>
<button class="minus">-</button>
</div>
<div class="single-total" data-value="${cijena}">${cijena} KN</div>
</div>
`;
shoopingCart.innerHTML += singleItem;
const basketTotal = `
<div class="totalKosara vidljivo">
<div class="potvrdi">
<p class="sub">Subtotal</p>
<p class="price">675 KN</p>
</div>
<div class="text">
<p>Shipping, taxes and discounts calculated at checkout.</p>
</div>
<div class="blue"><button>Checkout</button></div>
</div>
`;
const removeElement = function () {
const nodes = document.querySelectorAll(`.single-item`);
let lastNode = nodes[nodes.length - 1];
console.log(lastNode);
};
removeElement();
//OBRISI ITEM
const deleteItem = document.querySelectorAll(`.deleteItem`);
deleteItem.forEach((btn) => {
btn.addEventListener(`click`, function (e) {
const mainEl = e.target.closest(`.single-item`);
mainEl.parentNode.removeChild(mainEl);
button.disabled = false;
});
});
//add more movies btn
const plusBtn = document.querySelectorAll(`.plus`);
const minusBtn = document.querySelectorAll(`.minus`);
plusBtn.forEach((btn) => {
btn.addEventListener(`click`, function (e) {
let plus = e.target;
let parent = plus.closest(`.kolicina`);
let input = parent.querySelector(`.input`);
let singleEl = parent.closest(`.single-item`);
let singleTotal = singleEl.querySelector(`.single-total`);
input.value++;
if (input.value > 3) input.value = 3;
singleTotal.innerText = `${
singleTotal.dataset.value * input.value
} KN`;
});
});
minusBtn.forEach((btn) => {
btn.addEventListener(`click`, function (e) {
let plus = e.target;
let parent = plus.closest(`.kolicina`);
let input = parent.querySelector(`.input`);
let singleEl = parent.closest(`.single-item`);
let singleTotal = singleEl.querySelector(`.single-total`);
input.value--;
console.log(input.innerText);
if (input.value < 1) input.value = 1;
singleTotal.innerText = `${
singleTotal.dataset.value * input.value
} KN`;
});
});
});
});
});
})
.catch(
(err) => console.error(err));
I couldn't understand clearly what you are trying to say. But as far as considered to append a child to parent div you can use
parentDiv.appendChild(childElement);
Appreciate it if you can make the question more understable.

How to I add error messages as per the error in HTML

Currently the Error message that is displayed is common for all the errors . But i want to display different error messages for different errors. Like for Invalid password it should display invalid password. Whereas for invalid username it should display invalid username.
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
font-family: Arial, Helvetica, sans-serif;
display: grid;
justify-items: center;
align-items: center;
background-color: #d39090;
}
#main-holder {
width: 50%;
height: 70%;
display: grid;
justify-items: center;
align-items: center;
background-color: white;
border-radius: 7px;
box-shadow: 0px 0px 5px 2px black;
}
#signup-error-msg-holder {
width: 100%;
height: 100%;
display: grid;
justify-items: center;
align-items: center;
}
#signup-error-msg {
width: 23%;
text-align: center;
margin: 0;
padding: 5px;
font-size: 16px;
font-weight: bold;
color: #8a0000;
border: 1px solid #8a0000;
background-color: #e58f8f;
opacity: 0;
}
#error-msg-second-line {
display: block;
}
#signup-form {
align-self: flex-start;
display: grid;
justify-items: center;
align-items: center;
}
.signup-form-field::placeholder {
color: #2e4136;
}
.signup-form-field {
border: none;
border-bottom: 1px solid #755ddf;
margin-bottom: 10px;
border-radius: 3px;
outline: none;
padding: 0px 0px 5px 5px;
}
#signup-form-submit {
width: 100%;
margin-top: 20px;
padding: 10px;
border: none;
border-radius: 5px;
color: white;
font-weight: bold;
background-color: #43509b;
cursor: pointer;
outline: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sign Up Page</title>
<link rel="stylesheet" href="interlog.css">
</head>
<body>
<main id="main-holder">
<h1 id="signup-header"><b>Sign Up</b></h1>
<div id="signup-error-msg-holder">
<p id="signup-error-msg">Invalid username <span id="error-msg-second-line">and/or password</span></p>
</div>
<form id="signup-form">
<input type="text" name="username" id="username-field" class="signup-form-field" placeholder="Username">
<input type="password" name="password" id="password-field" class="signup-form-field" placeholder="Password">
<input type="submit" value="submit" id="signup-form-submit">
</form>
</main>
<script>
const signupForm = document.getElementById("signup-form");
const signupButton = document.getElementById("signup-form-submit");
const signupErrorMsg = document.getElementById("signup-error-msg");
signupButton.addEventListener("click", (e) => {
e.preventDefault();
const username = signupForm.username.value;
const password = signupForm.password.value;
if (username === "admin" && password === "password") {
alert("You have successfully logged in.");
location.reload();
} else {
signupErrorMsg.style.opacity = 1;
}
})
</script>
</body>
</html>
Can someone Please tell me How should i do that. I tried adding another message at and making the necessary changes in javascript, but it would display both messages simultaneously.
`<div id="signup-error-msg-holder">
<p id="signup-error-msg1">Invalid password</p>
</div>
<div id="signup-error-msg-holder">
<p id="signup-error-msg2">Invalid username </p>
</div>
`
const signupErrorMsg1 = document.getElementById("signup-error-msg1");
const signupErrorMsg2 = document.getElementById("signup-error-msg2");
signupButton.addEventListener("click", (e) => {
e.preventDefault();
const username = signupForm.username.value;
const password = signupForm.password.value;
if (username === "admin" && password === "password") {
alert("You have successfully logged in.");
location.reload();
} else if (username === "admin" && password !== "password") {
signupErrorMsg1.style.opacity = 1;
} else if (username !== "admin" && password === "password") {
signupErrorMsg2.style.opacity = 1;
}
})
`
Any help would be appreciated .
Test each and push to an error array. If the array has zero length the tests passed
const signupForm = document.getElementById("signup-form");
const signupButton = document.getElementById("signup-form-submit");
const signupErrorMsg = document.getElementById("signup-error-msg");
signupButton.addEventListener("click", (e) => {
e.preventDefault();
const username = signupForm.username.value;
const password = signupForm.password.value;
const msg = []
if (username !== "admin") msg.push("username")
if (password !== "password") msg.push("password")
if (msg.length === 0) {
alert("You have successfully logged in.");
location.reload();
return;
}
signupErrorMsg.textContent = "Invalid " + msg.join(" and ");
signupErrorMsg.style.opacity = 1;
})
html {
height: 100%;
}
body {
height: 100%;
margin: 0;
font-family: Arial, Helvetica, sans-serif;
display: grid;
justify-items: center;
align-items: center;
background-color: #d39090;
}
#main-holder {
width: 50%;
height: 70%;
display: grid;
justify-items: center;
align-items: center;
background-color: white;
border-radius: 7px;
box-shadow: 0px 0px 5px 2px black;
}
#signup-error-msg-holder {
width: 100%;
height: 100%;
display: grid;
justify-items: center;
align-items: center;
}
#signup-error-msg {
width: 23%;
text-align: center;
margin: 0;
padding: 5px;
font-size: 16px;
font-weight: bold;
color: #8a0000;
border: 1px solid #8a0000;
background-color: #e58f8f;
opacity: 0;
}
#error-msg-second-line {
display: block;
}
#signup-form {
align-self: flex-start;
display: grid;
justify-items: center;
align-items: center;
}
.signup-form-field::placeholder {
color: #2e4136;
}
.signup-form-field {
border: none;
border-bottom: 1px solid #755ddf;
margin-bottom: 10px;
border-radius: 3px;
outline: none;
padding: 0px 0px 5px 5px;
}
#signup-form-submit {
width: 100%;
margin-top: 20px;
padding: 10px;
border: none;
border-radius: 5px;
color: white;
font-weight: bold;
background-color: #43509b;
cursor: pointer;
outline: none;
}
<main id="main-holder">
<h1 id="signup-header"><b>Sign Up</b></h1>
<div id="signup-error-msg-holder">
<p id="signup-error-msg"></p>
</div>
<form id="signup-form">
<input type="text" name="username" id="username-field" class="signup-form-field" placeholder="Username">
<input type="password" name="password" id="password-field" class="signup-form-field" placeholder="Password">
<input type="submit" value="submit" id="signup-form-submit">
</form>
</main>

Strange behavior while adding DOM element using addEventListener() on a button

I'm trying to create a project card with user info when the user clicks on a button. When the user clicks the new project button, a modal form pops up that takes the user info and has a create button. The program should add a new project card whenever the user clicks the create button. To achieve this I added a click event listener to the Add new project button and another to Create button. I nested the create event listener inside the add new project event listener.
Here's the event listener.
addTileBtn.addEventListener("click", (e) => {
e.preventDefault();
modal.style.display = "block";
const titleField = document.querySelector("#title");
const descriptionField = document.querySelector("#description");
const create = document.querySelector("#create");
const close = document.querySelector("#close");
create.addEventListener("click", (e) => {
e.preventDefault();
title = titleField.value;
description = descriptionField.value;
function createProjectTile() {
const projectTile = document.createElement("div");
projectTile.classList.add("cards-grid__tile");
projectTile.textContent = title;
console.log(title, description);
return projectTile;
}
cardsGrid.appendChild(createProjectTile());
modal.style.display = "none";
});
close.addEventListener("click", (e) => {
e.preventDefault();
modal.style.display = "none";
});
});
The problem is that when I create the first card it works fine. But the second time, it creates two cards and 3 cards on the 3rd time and so on.
Here is the JSFiddle link for the full code.
I've edited your code, this should be what you wanted:
const logoutBtn = document.querySelector("#logout");
const addTileBtn = document.querySelector("#add-tile");
const cardsGrid = document.querySelector(".cards-grid");
const modal = document.querySelector(".modal");
const titleField = document.querySelector("#title");
const descriptionField = document.querySelector("#description");
const create = document.querySelector("#create");
const close = document.querySelector("#close");
addTileBtn.addEventListener("click", (e) => {
e.preventDefault();
modal.style.display = "block";
titleField.value = "";
descriptionField.value = "";
});
create.addEventListener("click", (e) => {
e.preventDefault();
title = titleField.value;
description = descriptionField.value;
function createProjectTile() {
const projectTile = document.createElement("div");
projectTile.classList.add("cards-grid__tile");
projectTile.textContent = title;
console.log(title, description);
return projectTile;
}
cardsGrid.appendChild(createProjectTile());
modal.style.display = "none";
});
close.addEventListener("click", (e) => {
e.preventDefault();
modal.style.display = "none";
});
:root {
--main-red: #be3144;
--main-white: #f0f0f0;
--main-gray: #303841;
--main-blue: #45567d;
--main-blue3: #1c262f;
--main-blue2: #27333d;
--main-blue1: #2e3d49;
--main-light-blue: #02b3e4;
--main-black: #000000;
--main-light-black: #3a3d40;
--main-dark-black: #181719;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
img {
display: block;
max-width: 100%;
height: auto;
}
body {
font-family: "Poppins", sans-serif;
font-size: 1.8rem;
font-weight: 400;
line-height: 1.4;
color: var(--main-white);
}
h1,
h2 {
font-family: "Raleway", sans-serif;
font-weight: 700;
text-align: center;
}
h1 {
font-size: 3.5rem;
}
h2 {
font-size: 2rem;
color: var(--main-blue);
display: block;
}
p {
font-size: 1.8rem;
font-weight: 200;
font-style: italic;
color: var(--main-white);
}
a {
text-decoration: none;
text-align: center;
display: block;
}
.main {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 100vh;
background-color: var(--main-white);
}
.box {
border: none;
box-shadow: 0 2px 4px rgb(0 0 0 / 10%), 0 8px 16px rgb(0 0 0 / 10%);
border-radius: 8px;
background-color: #fff;
}
.box__fields {
padding: 20px;
}
.box-field {
margin-bottom: 20px;
display: flex;
justify-content: center;
}
.icon {
position: absolute;
padding: 10px;
color: gray;
min-width: 50px;
text-align: center;
font-size: 20px;
top: 50%;
transform: translateY(-50%);
}
input,
textarea {
font-size: 17px;
padding: 14px 16px;
width: 300px;
cursor: text;
border: 1px solid var(--main-gray);
border-radius: 6px;
outline: none;
padding-left: 45px;
}
.box-btn {
border: none;
border-radius: 6px;
font-size: 20px;
line-height: 48px;
padding: 0 16px;
}
.app,
.main-content {
height: 100%;
}
.title-area {
background-color: var(--main-blue3);
width: 100%;
font-size: 18px;
min-height: 60px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
position: fixed;
top: 0;
left: 0;
}
.title-area__item {
padding: 10px 30px;
}
.logout-btn {
border: none;
border-radius: 6px;
font-size: 20px;
line-height: 30px;
padding: 0 16px;
width: 100px;
cursor: pointer;
color: #fff;
background-color: var(--main-light-blue);
}
.logout-btn:hover {
background-color: #029be4;
}
.content-area {
margin-top: 60px;
width: 100%;
height: 100%;
overflow: auto;
background-color: var(--main-blue);
}
.cards-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 50px;
margin-bottom: 3rem;
padding: 5rem 3rem;
}
.cards-grid__tile {
background-color: var(--main-blue2);
max-width: 200px;
padding: 30px;
text-align: center;
font-size: 1.2rem;
}
.add-tile-btn {
border: none;
border-radius: 6px;
font-size: 15px;
line-height: 48px;
padding: 0 10px;
cursor: pointer;
color: #fff;
background-color: var(--main-light-blue);
}
.modal {
display: none;
width: 350px;
font-size: 1.2rem;
position: relative;
top: 10%;
left: 50%;
transform: translateX(-50%);
overflow: visible;
}
.box {
background-color: var(--main-blue1);
opacity: 0.95;
}
.box-field {
flex-direction: column;
}
input,
textarea {
padding: 5px 10px;
resize: none;
}
.wrapper {
position: relative;
text-align: center;
}
.create-btn {
width: 100px;
cursor: pointer;
color: #fff;
background-color: var(--main-light-blue);
}
.close {
cursor: pointer;
position: absolute;
top: 20px;
left: 290px;
}
#modal-form {
position: absolute;
}
.icon {
color: var(--main-blue3);
}
<div class="app">
<div class="nav-wrapper">
<nav id="nav" class="nav"></nav>
</div>
<div class="main-content">
<div class="title-area">
<div class="title-area__item">Menu</div>
<div class="title-area__item">Boards</div>
<div class="title-area__item">
<button id="logout" class="logout-btn btn">
Logout
</button>
</div>
</div>
<div class="content-area">
<div class="modal">
<form id="modal-form" class="box">
<a id="close" class="close">
<i class="fa fa-times icon">close</i>
</a>
<div class="box__fields">
<div class="box-field">
<label for="title"> Title </label>
<input
id="title"
type="text"
name="title"
required
autofocus
/>
</div>
<div class="box-field">
<label for="description">
Description
</label>
<textarea
id="description"
name="title"
rows="6"
cols="40"
></textarea>
</div>
<div class="box-field">
<div class="wrapper">
<button
id="create"
class="create-btn box-btn btn"
>
Create
</button>
</div>
</div>
</div>
</form>
</div>
<div class="cards-grid">
<div class="cards-grid__tile">
<button id="add-tile" class="add-tile-btn btn">
+ Add new project
</button>
</div>
</div>
</div>
</div>
</div>

How do I create a filter for content displayed using Javascript?

I'm building a film review site, where all of the content is generated on the main page from data input in the admin panel and placed into a container div.
I've got a basic sorting system (by ID, ascending/descending) already which works fine on my end, but I also want to be able to filter the films by genre (e.g if film is marked as Action on database, make all non-action films hidden.
This cannot be done by CSS alone as I'm not able to add classes to the content within the containers, the container for the film image is generated via JS.
I'm assuming I need to create a new function such as
function getFilmListByGenre(genreName)
Or something along those lines, but I don't know how I'd make it work.
Here is the current Javascript that I have, which creates the sort feature.
let db = new PouchDB('films');
let radios = document.getElementsByName("sort");
radios[0].addEventListener("change", getFilmList);
radios[1].addEventListener("change", getFilmList);
getFilmList();
function getFilmList(){
db.allDocs({include_docs: true, descending: radios[0].checked}).then(function(films){
let listContents = '';
for(let i = 0; i < films.total_rows; i++) {
let thisFilm = films.rows[i].doc;
let image = '<a class="btn" href="viewFilm.html?id=' + thisFilm._id +'"><img class="filmImage" src="' + thisFilm.image +'"></a>';
listContents += '<div class="filmRow">'+ image + '</div>';
}
document.getElementById('filmContainer').innerHTML = listContents;
})
}
I basically want to grab the value for genre (which can only be "Action", "Comedy", "Horror" or "Other") for each film from the database, then if the corresponding radio (named filter) is selected, all of the films which aren't labelled as that genre are hidden.
#import url(https://fonts.googleapis.com/css?family=Raleway);
body {
margin: 0;
font-family: 'Raleway', georgia, arial;
background-color: #e0e0e0;
text-align: center;
}
h1 {
color: #aaaaaa;
text-align: left;
}
.sortFilms {
text-align: left;
display: inline-block;
background-color: #ff6699;
width: 80%;
padding: 20px;
}
header {
text-align: center;
display: inline-block;
border-bottom: 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-style: solid;
border-color: #aaaaaa;
width: 80%;
padding: 20px;
background-color: #e0e0e0;
}
.newFilm {
text-align: left;
display: inline-block;
background-color: #ff6699;
width: 80%;
padding: 20px;
}
label {
font-size: 1em;
padding: 6px;
color: #fff;
font-weight: 700;
display: block;
text-align: left;
}
.form {
margin: auto;
display: flex;
text-align: center;
flex-direction: column;
}
h2 {
font-weight: 700;
font-size: 2em;
width: 50%;
color: #B2365F;
}
#formTitle {
margin-top: 0;
margin-bottom: 0;
}
.row {
margin-left: -20px;
display: grid;
grid-template-columns: 1fr 1fr;
}
.col {
padding: 20px;
}
input,
textarea, select {
width: 100%;
display: block;
border-radius: 25px;
background-color: #e0e0e0;
padding: 10px;
border: none;
box-sizing:border-box; }
}
.tagline {
margin: 0;
color: #333333;
font-size: 1em;
font-weight: 700;
}
input::placeholder {
color: #000;
}
textarea::placeholder {
color: #000;
}
#modifyFilmButton {
float: right;
}
#media only screen and (max-width: 700px) {
.row {
grid-template-columns: 1fr;
}
}
#media screen and (max-width:800px) {
table {
border: 0;
}
table caption {
font-size: 1.3em;
}
table thead {
border: none;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
table tr {
border: 2px solid #e0e0e0;
background-color: #e0e0e0;
display: block;
margin-bottom: .625em;
border-radius: 20px;
}
table td {
display: block;
font-weight: bold;
font-size: 1.2em;
text-align: left;
padding: 15px;
}
table td::before {
/*
* aria-label has no advantage, it won't be read inside a table
content: attr(aria-label);
*/
content: attr(data-label);
float: left;
font-weight: bold;
text-transform: uppercase;
}
table td:last-child {
border-bottom: 0;
}
}
.oldFilm {
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
text-align: left;
display: inline-block;
background-color: #AAAAAA;
width: 80%;
padding: 20px;
}
#oldTitle {
margin-top: 0;
margin-bottom: 0;
color: #ff6699;
padding-bottom: 20px;
}
td {
padding: 5px;
font-weight: bold;
}
table {
border-collapse: collapse;
text-align: center;
width: 100%;
}
thead {
background: #ff6699;
}
.reviewImage {
width: 200px;
border-radius: 20px;
}
.filmRow img {
width: 300px;
height: 420px;
margin: 10px;
border-radius: 20px;
}
.filmRow {
-webkit-flex-flow: row wrap;
justify-content: space-around;
}
#filmContainer {
width: 100%;
margin-top: 10px;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-around;
}
#date {
padding: 5px;
text-align: left;
width: 30%;
}
#date input {
width: auto;
}
#date label {
display: -webkit-inline-box;
}
#oldTitle2 {
margin-top: 0;
margin-bottom: 0;
color: #ff6699;
}
.genre {
padding: 5px;
text-align: left;
width: 60%;
}
.genre input {
width:auto;
}
.genre label {
display: -webkit-inline-box;
}
<div class="sortFilms">
<h2 id="formTitle">Latest reviews</h2>
<div id='filmContainer'></div>
</div>
<div class="oldFilm">
<h2 id="oldTitle2">Sort by</h2>
<div id="date">
<p><b>Age of review</b></p>
<label>Newer<input type="radio" name="sort" checked/></label>
<label>Older<input type="radio" name="sort"/></label>
</div>
<div class="genre">
<p><b>Genre</b></p>
<label>Action<input type="radio" name="filter"/></label>
<label>Comedy<input type="radio" name="filter"/></label>
<label>Horror<input type="radio" name="filter"/></label>
<label>Other<input type="radio" name="filter"/></label>
</div>
</div>
You should seperate your display logic and your fetching logic, then you can just filter out the results that aren't the genre you wanted. I would do it something like this:
var db = {
allDocs: () => {
return new Promise((resolve) => resolve([{genre: 'Horror', title: 'The Hills Have Eyes'}, {genre: 'Comedy', title: 'Dumb and Dumber'}]))
}
}
function getFilmList() {
return db.allDocs();
}
function getFilmsByGenre(genre) {
return getFilmList().then(films => films.filter(film => film.genre === genre));
}
function displayFilms(films) {
let listContents = '';
for(let i = 0; i < films.length; i++) {
let thisFilm = films[i].title;
listContents += '<div class="filmRow">'+ thisFilm + '</div>';
}
document.getElementById('filmContainer').innerHTML = listContents;
}
document.getElementById('all').addEventListener('click', () => {
getFilmList().then(displayFilms)
})
document.querySelectorAll('[name="filter"]').forEach(radio => radio.addEventListener('change', (event) => {
getFilmsByGenre(event.target.parentNode.textContent).then(displayFilms)
}))
<div id="filmContainer"></div>
<button id="all">All</button>
<label>Action<input type="radio" name="filter"/></label>
<label>Comedy<input type="radio" name="filter"/></label>
<label>Horror<input type="radio" name="filter"/></label>
<label>Other<input type="radio" name="filter"/></label>

Categories