I need to understand how to connect peers in gun db. I have a socket.io server deployed on heroku but I don't know if it will work with gun. Can anyone with experience with gun db help me with this? I've readed the documentations but it's not clear how the peers are connected and there isn't a clear code example on the documentation.
I've tested the chat example, but it will not work on my localhost server, I will not be able to deploy it on my shared hosting because sockets are not permitted. Also on localhost messages are not delivered between two different browser windows.
UPDATE :
Here is the code with the suggested lib/webrtc added. Still not working.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Converse</title>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0">
<link rel="stylesheet" type="text/css" href="../style.css">
<link href='https://fonts.googleapis.com/css?family=Poiret+One' rel='stylesheet' type='text/css'>
<style>
.chat__heading {
position: fixed;
text-align: center;
z-index: 1;
width: 100%;
margin-top: 0;
margin-bottom: 0;
}
.chat__form-container {
display: flex;
justify-content: center;
width: 100%;
padding: 10px 20px;
position: fixed;
z-index: 1;
bottom: 0;
}
.chat__form {
display: flex;
justify-content: center;
height: 50px;
background-color: white;
border: 2px solid white;
max-width: 900px;
width: 100%;
border-radius: 5px;
}
.chat__name-input {
flex: 1;
padding: 10px;
}
.chat__message-input {
flex: 5;
padding: 10px;
}
.chat__submit {
padding: 10px;
color: white;
border-radius: 5px;
}
.chat__submit:hover::after {
background-color: rgba(0,0,0,0.2);
}
.chat__submit:focus::after {
background-color: rgba(0,0,0,0.2);
}
.chat__submit::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
border-radius: 5px;
transition: background-color 0.3s;
background-color: rgba(0,0,0,0);
}
.chat__message-list {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
overflow-y: auto;
padding: 60px 20px;
width: 100%;
background-color: rgba(0, 0, 0, 0.2);
min-height: 100vh;
}
.chat__message {
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
padding: 10px;
border-radius: 5px;
width: 100%;
position: relative;
max-width: 900px;
}
.chat__name {
margin-right: 20px;
}
.chat__when {
position: absolute;
top: 0;
right: 2em;
padding: 10px;
background: rgba(100%, 100%, 100%, 0.9);
opacity: 0;
border-radius: 5px;
}
.chat__message:hover .chat__when {
opacity: 1;
right: 0em;
}
#media (max-width: 567px) {
.chat__heading {
font-size: 30px;
}
}
</style>
</head>
<body>
<div class="chat hue2 page">
<h2 id='title' class="chat__heading hue2 whitet">Have a Conversation...</h2>
<ul class="chat__message-list">
<li class="none"></li>
</ul>
<div class="chat__form-container hue2">
<form class="chat__form">
<label for="name-input" class="visually-hidden">Name</label>
<input id="name-input" class="chat__name-input" placeholder="Name"></input>
<label for="message-input" class="visually-hidden">Message</label>
<input id="message-input" class="chat__message-input" placeholder="Write a message..."></input>
<button class="chat__submit say hue2">say</button>
</form>
</div>
<div class="model">
<li class="chat__message white huet2 box">
<b class="chat__name"></b>
<p class="chat__message-text"></p>
<span class="sort none">0</span>
<div class="chat__when"></div>
</li>
</div>
</div>
<script src="../jquery.js"></script>
<script src="../../gun.js"></script>
<script src="../../nts.js"></script>
<script src="../../lib/webrtc.js"></script>
<script>
var gun = Gun(document.location.host + ':443/gun');
var chat = gun.get('converse/' + location.hash.slice(1));
console.log(chat);
console.log(gun);
console.log(location.hash.slice(1));
$(".chat__submit").on('click', submit);
$(".chat_form").on('keydown', enter);
function enter(e) {
if (e.which !== 13) { return }
submit(e);
}
function submit(e) {
e.preventDefault();
var msg = { when: Gun.time.is() };
msg.who = $('.chat__name-input').val();
if (!msg.who) {
msg.who = 'user' + Gun.text.random(3);
$('.chat__name-input').val(msg.who);
}
msg.what = $('.chat__message-input').val();
if (!msg.what) { return }
chat.set(msg);
$('.chat__message-input').val('').focus();
}
chat.map().val(function (msg, id) {
if (!msg) { return }
var messageList = $('.chat__message-list');
var last = sort(msg.when, messageList.children('li').last());
var li = $("#msg-" + id)[0]; // grab if exists
if (!li) {
li = $('.model li').clone(true) // else create it
.attr('id', 'msg-' + id)
.insertAfter(last);
}
// bind the message data into the UI
li = $(li);
li.find('.chat__name').text(msg.who);
li.find('.chat__message-text').text(msg.what);
li.find('.sort').text(msg.when);
var time = new Date(msg.when);
li.find('.chat__when').text(time.toDateString() + ', ' + time.toLocaleTimeString());
$('html, body').stop(true, true)
.animate({ scrollTop: messageList.height() });
});
function sort(num, li) { return parseFloat(num) >= parseFloat($(li).find('.sort').text() || -Infinity) ? li : sort(num, li.prev()) }
</script>
</body>
</html>
wow #mauro-stepanoski 's comment is so good (it should be the answer)! #jihuuNI when the lib/webrtc adapter is added like in the Todo-Dapp tutorial, it attempts to automatically connect all browsers with all other browsers - in the future, AXE will automatically cut off unnecessary connections. Do note, browser's WebRTC feature is not very reliable, so you still want to also have super peer connections.
Related
I am making a small project where you can make flashcards that populate a grid inside of a div that has a class of "grid-cards". At the very bottom of my Codepen Javascript code you can see I attempted to save all the created flashcards to localStorage so when the user refreshes the created flashcards will still be there.
//Add Question button toggle and close button function
const addQuestionBtn = document.querySelector("#add-question")
const formContainer = document.querySelector(".hidden")
const closeBtn = document.querySelector("#close-btn")
addQuestionBtn.addEventListener("click", function addBtnToggle() {
if (formContainer.className == "hidden") {
formContainer.classList.remove("hidden")
formContainer.classList.add("form-container")
} else if (formContainer.className == "form-container") {
formContainer.classList.remove("form-container")
formContainer.classList.add("hidden")
}
})
closeBtn.addEventListener("click", function closeForm() {
if (formContainer.className == "form-container") {
formContainer.classList.remove("form-container")
formContainer.classList.add("hidden")
}
})
//Form event listener / Creating cards to populate grid
const questionInput = document.querySelector("#question-input")
const answerInput = document.querySelector("#answer-input")
const saveBtn = document.querySelector("#save-btn")
const form = document.querySelector("form")
const grid = document.querySelector(".grid-cards")
form.addEventListener("submit", function sumbit(e) {
e.preventDefault()
//Creating elements
let questionValue = questionInput.value
let answerValue = answerInput.value
let div = document.createElement("div")
div.classList.add("card")
let h3 = document.createElement("h3")
h3.setAttribute("id", "question")
showHideAnswer = document.createElement("a")
showHideAnswer.setAttribute("href", "")
showHideAnswer.innerHTML = "Show/Hide Answer"
let p = document.createElement("p")
p.classList.add("hidden")
let deleteBtn = document.createElement("button")
deleteBtn.setAttribute("id", "deleteBtn")
//Appending created elements to div
grid.appendChild(div)
div.append(h3)
div.append(showHideAnswer)
div.append(p)
div.append(deleteBtn)
h3.innerHTML = questionValue
p.innerHTML = answerValue
deleteBtn.innerHTML = "Delete"
//Show and hide answer
showHideAnswer.addEventListener("click", function showAnswer(e) {
e.preventDefault()
if (p.className == "hidden") {
p.classList.remove("hidden")
p.classList.add("answer")
} else if (p.className == "answer") {
p.classList.remove("answer")
p.classList.add("hidden")
}
})
//Delete a flashcard
deleteBtn.addEventListener("click", function deleted() {
grid.removeChild(div)
})
//Local storage
//Gathering all the inner HTML from my grid which the created flashcards sit in
localStorage.setItem("innerContent", grid.innerHTML)
const innerContent = localStorage.getItem("innerContent")
//Attempting to populate the grid with the users created cards
grid.innerHTML = inner
})
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
}
.container {
max-width: 1100px;
width: 100%;
}
.header {
padding: 25px 0;
}
#add-question {
margin-top: 15px;
padding: 10px 15px;
}
.innerForm-container {
background-color: rgb(219, 219, 219);
padding: 20px;
width: 500px;
border: 2px solid black;
position: relative;
}
h2 {
margin-top: 10px;
}
#question-input {
margin-top: 10px;
width: 100%;
height: 70px;
}
#answer-input {
margin-top: 10px;
width: 100%;
height: 70px;
}
#save-btn {
margin-top: 15px;
padding: 10px 100px;
}
#close-btn {
position: absolute;
top: 5px;
right: 5px;
padding: 15px 20px;
}
.hidden {
display: none;
}
.grid-cards {
display: grid;
grid-template-columns: repeat(3, 350px);
grid-template-rows: repeat(5, 200px);
grid-column-gap: 25px;
grid-row-gap: 25px;
justify-content: center;
margin-top: 20px;
}
.card {
background-color: rgb(230, 230, 230);
border: 1px solid black;
border-radius: 15px;
padding: 15px;
position: relative;
}
h3 {
font-size: 22px;
}
p {
margin-top: 15px;
}
a {
margin-top: 25px;
display: block;
}
#deleteBtn {
padding: 10px 20px;
position: absolute;
bottom: 15px;
right: 15px;
}
.hidden {
display: none;
}
<!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">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="inner-container">
<div class="header">
<h1>Flashcards</h1>
<button id="add-question">Add Question</button>
</div>
<div class="hidden">
<div class="innerForm-container">
<form action="">
<h2>Question</h2>
<textarea name="" id="question-input" cols="30" rows="10"></textarea>
<h2>Answer</h2>
<textarea name="" id="answer-input" cols="30" rows="10"></textarea>
<button id="save-btn">Save</button>
<button id="close-btn">X</button>
</form>
</div>
</div>
<div class="grid-cards">
</div>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
I am trying to get the content from and then trying to repopulate it again after refreshing the page so basically all of the users created flashcards will be saved.
You are properly saving the content of the grid. However, you are just not loading it into the grid when the page is loaded.
To do so, just add:
grid.innerHTML = localStorage.getItem('innerContent')
I am making a small project where you can make flashcards that populate a grid inside of a div that has a class of "grid-cards". At the very bottom of my Codepen Javascript code you can see I attempted to save all the created flashcards to localStorage so when the user refreshes the created flashcards will still be there.
//Add Question button toggle and close button function
const addQuestionBtn = document.querySelector("#add-question")
const formContainer = document.querySelector(".hidden")
const closeBtn = document.querySelector("#close-btn")
addQuestionBtn.addEventListener("click", function addBtnToggle() {
if (formContainer.className == "hidden") {
formContainer.classList.remove("hidden")
formContainer.classList.add("form-container")
} else if (formContainer.className == "form-container") {
formContainer.classList.remove("form-container")
formContainer.classList.add("hidden")
}
})
closeBtn.addEventListener("click", function closeForm() {
if (formContainer.className == "form-container") {
formContainer.classList.remove("form-container")
formContainer.classList.add("hidden")
}
})
//Form event listener / Creating cards to populate grid
const questionInput = document.querySelector("#question-input")
const answerInput = document.querySelector("#answer-input")
const saveBtn = document.querySelector("#save-btn")
const form = document.querySelector("form")
const grid = document.querySelector(".grid-cards")
form.addEventListener("submit", function sumbit(e) {
e.preventDefault()
//Creating elements
let questionValue = questionInput.value
let answerValue = answerInput.value
let div = document.createElement("div")
div.classList.add("card")
let h3 = document.createElement("h3")
h3.setAttribute("id", "question")
showHideAnswer = document.createElement("a")
showHideAnswer.setAttribute("href", "")
showHideAnswer.innerHTML = "Show/Hide Answer"
let p = document.createElement("p")
p.classList.add("hidden")
let deleteBtn = document.createElement("button")
deleteBtn.setAttribute("id", "deleteBtn")
//Appending created elements to div
grid.appendChild(div)
div.append(h3)
div.append(showHideAnswer)
div.append(p)
div.append(deleteBtn)
h3.innerHTML = questionValue
p.innerHTML = answerValue
deleteBtn.innerHTML = "Delete"
//Show and hide answer
showHideAnswer.addEventListener("click", function showAnswer(e) {
e.preventDefault()
if (p.className == "hidden") {
p.classList.remove("hidden")
p.classList.add("answer")
} else if (p.className == "answer") {
p.classList.remove("answer")
p.classList.add("hidden")
}
})
//Delete a flashcard
deleteBtn.addEventListener("click", function deleted() {
grid.removeChild(div)
})
//Local storage
//Gathering all the inner HTML from my grid which the created flashcards sit in
localStorage.setItem("innerContent", grid.innerHTML)
const innerContent = localStorage.getItem("innerContent")
//Attempting to populate the grid with the users created cards
grid.innerHTML = inner
})
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
}
.container {
max-width: 1100px;
width: 100%;
}
.header {
padding: 25px 0;
}
#add-question {
margin-top: 15px;
padding: 10px 15px;
}
.innerForm-container {
background-color: rgb(219, 219, 219);
padding: 20px;
width: 500px;
border: 2px solid black;
position: relative;
}
h2 {
margin-top: 10px;
}
#question-input {
margin-top: 10px;
width: 100%;
height: 70px;
}
#answer-input {
margin-top: 10px;
width: 100%;
height: 70px;
}
#save-btn {
margin-top: 15px;
padding: 10px 100px;
}
#close-btn {
position: absolute;
top: 5px;
right: 5px;
padding: 15px 20px;
}
.hidden {
display: none;
}
.grid-cards {
display: grid;
grid-template-columns: repeat(3, 350px);
grid-template-rows: repeat(5, 200px);
grid-column-gap: 25px;
grid-row-gap: 25px;
justify-content: center;
margin-top: 20px;
}
.card {
background-color: rgb(230, 230, 230);
border: 1px solid black;
border-radius: 15px;
padding: 15px;
position: relative;
}
h3 {
font-size: 22px;
}
p {
margin-top: 15px;
}
a {
margin-top: 25px;
display: block;
}
#deleteBtn {
padding: 10px 20px;
position: absolute;
bottom: 15px;
right: 15px;
}
.hidden {
display: none;
}
<!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">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="inner-container">
<div class="header">
<h1>Flashcards</h1>
<button id="add-question">Add Question</button>
</div>
<div class="hidden">
<div class="innerForm-container">
<form action="">
<h2>Question</h2>
<textarea name="" id="question-input" cols="30" rows="10"></textarea>
<h2>Answer</h2>
<textarea name="" id="answer-input" cols="30" rows="10"></textarea>
<button id="save-btn">Save</button>
<button id="close-btn">X</button>
</form>
</div>
</div>
<div class="grid-cards">
</div>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
I am trying to get the content from and then trying to repopulate it again after refreshing the page so basically all of the users created flashcards will be saved.
You are properly saving the content of the grid. However, you are just not loading it into the grid when the page is loaded.
To do so, just add:
grid.innerHTML = localStorage.getItem('innerContent')
I dont know how but my hover in left arrow (#left) stop work suddenly. I dont change any line of code in css which can create this issue. I just change the some lines in js and when I start site in codepen it didin't work. (the right one works fine ;D)
code:
HTML
<html>
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Josefin+Sans&display=swap" rel="stylesheet">
<link rel=”stylesheet” href=”text/style.css”>
</head>
<body>
<div class="container">
<div id="left">
<svg viewBox="0 0 256 512" width="50" title="angle-left">
<path d="M31.7 239l136-136c9.4-9.4 24.6-9.4 33.9 0l22.6 22.6c9.4 9.4 9.4 24.6 0 33.9L127.9 256l96.4 96.4c9.4 9.4 9.4 24.6 0 33.9L201.7 409c-9.4 9.4-24.6 9.4-33.9 0l-136-136c-9.5-9.4-9.5-24.6-.1-34z" />
</svg>
</div>
<div id="slides">
<div id="slide1"></div>
<div id="slide2"></div>
<div id="slide3"></div>
</div>
<ul class="slide_pointers">
<li id="slide_pointer1"></li>
<li id="slide_pointer2"></li>
<li id="slide_pointer3"></li>
</ul>
<div id="right" >
<svg viewBox="0 0 256 512" width="50" title="angle-right">
<path d="M224.3 273l-136 136c-9.4 9.4-24.6 9.4-33.9 0l-22.6-22.6c-9.4-9.4-9.4-24.6 0-33.9l96.4-96.4-96.4-96.4c-9.4-9.4-9.4-24.6 0-33.9L54.3 103c9.4-9.4 24.6-9.4 33.9 0l136 136c9.5 9.4 9.5 24.6.1 34z" />
</svg>
</div>
</div>
</body>
</html>
CSS
body
{
background-color: #000;
}
.container
{
display: flex;
width: 1000px;
height: 500px;
border-radius: 25px;
margin: auto;
margin-top: 10%;
align-items: center;
font-family: 'Josefin Sans', sans-serif;
}
#slides
{
width: 600px;
height: 300px;
margin-top: -100px;
position: absolute;
padding: 100px;
}
.slide_pointers
{
width: 800px;
height: 50px;
position: relative;
margin-top: 400px;
margin-left: 70px;
}
.slide_pointers > li
{
float: left;
list-style-type: none;
height: 10px;
width: 100px;
background-color: #9c9c9c;
margin-left: 80px;
margin-top: 40px;
border-radius: 25px;
}
#destription
{
font-size: 30px;
}
#right
{
right: -60px;
}
#right:hover
{
opacity: 0.7;
}
#left
{
margin-right: 40px;
}
#left : hover
{
opacity: 0.7;
}
JS
var slide1 = {
object: document.querySelector("#slide1"),
name: "WORK",
destription: "I'm programing since I have 7 years old. I started with html, c++. Then I findout python and I can say that i love this language. I learned some c# for making games in unity. I use lua for LOVE engine to also making games. Now I endup with JS/HTML/CSS to be the greatest, youngest frontend developer.",
active: true,
color: "#751BB5",
};
var slide2 = {
object: document.querySelector("#slide2"),
name: "LEARNING",
destription: "Before I end primmary school I have course where we do robots and we programmmed they in C and Python. We won some tournamets (First and Seccound place's).",
active: false,
color: "#14cba8",
};
var slide3 = {
object: document.querySelector("#slide3"),
name: "PASSION",
destription: "Since I have started learning programing my only reason to started it was dream to create something big. Something that anyone will remember for years. And this dream pushes me to learn more.",
active: false,
color: "#7ecb20",
};
var slide_pointer1 = {
object: document.querySelector("#slide_pointer1"),
};
var slide_pointer2 = {
object: document.querySelector("#slide_pointer2"),
};
var slide_pointer3 = {
object: document.querySelector("#slide_pointer3"),
};
var buttonLeft = document.querySelector("#right");
var buttonRight = document.querySelector("#left");
var container = document.querySelector(".container");
let slides = [slide1, slide2, slide3];
let slide_pointers = [slide_pointer1, slide_pointer3, slide_pointer2]
Refresh();
buttonRight.onclick = function WaitForClickRight()
{
for(let i = 0; i<3; i++)
{
if(slides[i].active)
{
if(i + 1 == 3)
{
slides[0].active = true;
slides[i].active = false;
}
else
{
slides[i+1].active = true;
slides[i].active = false;
}
Refresh();
break;
}
}
}
buttonLeft.onclick = function WaitForClickLeft()
{
for(let i = 0; i<3; i++)
{
if(slides[i].active)
{
if(i - 1 == -1)
{
slides[i].active = false;
slides[2].active = true;
}
else
{
slides[i].active = false;
slides[i-1].active = true;
}
Refresh();
break;
}
}
}
function Refresh()
{
for(let i = 0; i<3; i++)
{
if(slides[i].active == true)
{
slides[i].object.innerHTML = "<h1>" + slides[i].name + "</h1> <br> <p id='destription'>" + slides[i].destription + "</p>";
container.style.backgroundColor = slides[i].color;
slide_pointers[i].object.style.backgroundColor = "#484848";
}
else
{
slides[i].object.innerHTML = "";
slide_pointers[i].object.style.backgroundColor = "#9c9c9c";
}
}
}
and codepen: https://codepen.io/pawe-wojas/pen/NWYygWp
In the codepen, you had #left.hover instead of #left:hover
I changed the CSS to the below and it worked for me.
body
{
background-color: #000;
}
.container
{
display: flex;
width: 1000px;
height: 500px;
border-radius: 25px;
margin: auto;
margin-top: 10%;
align-items: center;
font-family: 'Josefin Sans', sans-serif;
}
#slides
{
width: 600px;
height: 300px;
margin-top: -100px;
margin-left: 100px;
position: absolute;
padding: 100px;
}
.slide_pointers
{
width: 800px;
height: 50px;
position: relative;
margin-top: 400px;
margin-left: 70px;
}
.slide_pointers > li
{
float: left;
list-style-type: none;
height: 10px;
width: 100px;
background-color: #9c9c9c;
margin-left: 80px;
margin-top: 40px;
border-radius: 25px;
}
#destription
{
font-size: 30px;
}
#right
{
right: -60px;
}
#right:hover
{
opacity: 0.7;
}
#left
{
margin-right: 40px;
}
#left:hover
{
opacity: 0.7;
}
Your content in slide is overlay left arrow, it will work when you try to add margin-left: 100px; on slides class.
"use strict";
const openModal = document.querySelector('[data-create]');
const exitModal = document.querySelector('[data-close]');
const saveBtn = document.querySelector('#save');
openModal.addEventListener('click', showModal);
exitModal.addEventListener('click', closeModal);
saveBtn.addEventListener('click', saveCard);
/*
Detects if text has been inputed. If not, an error is shown
if yes the createFlashCard and closed modal function are called.
*/
function saveCard() {
let questionArea = document.querySelector('#question');
let answerArea = document.querySelector('#answer');
let showAlert = document.querySelector('.show-error-message');
if (questionArea = null || questionArea.value == '') {
if (answerArea = null || answerArea.value == '') {
showAlert.classList.remove("hide-error");
}
setTimeout(() => {
showAlert.classList.add("hide-error");
}, 3000);
} else {
closeModal();
createFlashCard();
}
}
/*
Removes the is-hidden css class to open modal
*/
function showModal(e) {
let modal = document.querySelector('.modal-design');
modal.classList.remove("is-hidden");
}
/*
Adds the is-hidden css class to close modal
*/
function closeModal() {
let modal = document.querySelector('.modal-design');
modal.classList.add('is-hidden');
}
/*
Creates a flash card using input string values.
Then renders a card using the .innerHTML property.
Each card rendered will be clickable to show the answer.
*/
function createFlashCard() {
let questionText = document.querySelector('.question-text').value;
let answerText = document.querySelector('.answer-text').value;
let cardSection = document.querySelector('.card-container');
let createArticle = document.createElement('article');
createArticle.className += "card";
createArticle.innerHTML = `
<div class="card-question-button">
<h4 id="title">${questionText}</h4>
<button id="show">></button>
</div>
<div id="answer-card">
<p id="answer-card-p">${answerText}</p>
</div>`;
cardSection.appendChild(createArticle);
openCloseCards();
}
function openCloseCards() {
let buttons = document.querySelectorAll('.card-question-button');
buttons.forEach(function (btn) {
btn.addEventListener('click', function (e) {
let questions = e.currentTarget.parentElement;
questions.classList.toggle("show-text");
})
})
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
line-height: 1.5;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
/*
variables
*/
:root {
--primary-color:#5dcbd8;
--secondary-color: hsl(186, 100%, 94%);
--third-color: #F6F6F8;
--fourth-color: #fff;
--button-border: none;
--error-color: hsl(0deg 58% 70%);
--shadow: 0px 2px 3px 0 hsla(0 , 0%, 0%, 0.2);
}
header {
padding: 15px;
color: var(--third-color);
height: 100px;
background-color: var(--primary-color);
}
/**
Prompt question card
*/
.prompt-question {
display: flex;
padding: 15px;
align-items: center;
justify-content: space-around;
}
#create {
border: var(--button-border);
border-radius: 5px;
background-color: var(--secondary-color);
height: 60px;
width: 70px;
font-size: 25px;
transition: .3s ease-in-out;
}
#create:hover {
cursor: pointer;
background-color: #b5f0f7;
}
/*
Modal Design
*/
.modal-placement{
display: flex;
justify-content: center;
}
.modal-design {
width: 600px;
padding: 20px;
display: flex;
flex-direction: column;
justify-content: space-between;
background-color: #F6F6F8;
box-shadow:var(--shadow);
border-radius: 4px;
margin: 30px;
}
.is-hidden {
visibility: hidden;
opacity: 1;
}
.erase-modal-c {
display: flex;
justify-content: flex-end;
}
#erase {
background-color:var(--error-color);
display: flex;
justify-content: center;
border: none;
padding: 5px;
height: 25px;
width: 25px;
}
#close {
margin-top: -8px;
margin-left: 3px;
font-size: 20px;
transform: rotate(45deg);
}
#erase:hover {
cursor: pointer;
}
h3 {
padding-top: 15px;
}
/**
Textarea design
*/
#question, #answer {
height: 90px;
}
textarea {
font-size: 15px;
padding: 4px;
resize: vertical;
}
#save {
border: var(--button-border);
margin-top: 25px;
height: 45px;
font-size: 15px;
background-color:var(--primary-color);
color: var(--third-color);
}
#save:hover {
cursor: pointer;
background-color: #90d8e0;
}
.show-error-message {
background-color: var(--error-color);
color: var(--fourth-color);
margin-top: 15px;
padding: 10px;
text-align: center;
}
.hide-error {
visibility: hidden;
opacity: 0;
}
/*
Card container
*/
.card-container {
display: grid;
background-color: var(--third-color);
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr;
margin-top: 40px;
}
#title {
margin-left: 10px;
}
.card {
display: flex;
margin: 20px;
flex-direction: column;
align-items: center;
background-color:var(--fourth-color);
padding: 7px;
justify-content: space-between;
box-shadow:var(--shadow);
border-radius: 5px;
transition: .3s ease-in-out;
z-index: 1000;
}
.card-question-button {
display: flex;
justify-content: space-between;
padding: 5px;
width: 100%;
}
.card-question-button:hover {
cursor: pointer;
}
/*
Answer card
*/
#answer-card {
display: none;
border-top: 1px solid rgba(0, 0, 0, 0.2);
padding: 15px;
text-align: left;
}
#answer-card-p {
text-align: left;
}
.show-text #answer-card {
display: block;
}
#show {
border: none;
background-color: var(--fourth-color);
font-size: 20px;
transition: .2s ease-in-out;
}
#show:hover {
cursor:pointer;
transform: translateX(-2px);
}
/* Media Queries */
#media screen and (max-width: 800px) {
.prompt-question {
box-shadow:var(--shadow);
border-radius: 4px;
margin: 20px;
}
.card-container {
grid-template-columns: 1fr;
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<header>
<h1>Flash Cards +</h1>
</header>
<article class="prompt-question">
<button id="create" data-create>+</button>
<p class="info">
Create a new card
</p>
</article>
<article class="modal-placement">
<section class="modal-design is-hidden">
<div class="erase-modal-c">
<button id="erase" data-close>
<p id="close">+</p>
</button>
</div>
<h3>Question</h3>
<textarea class="question-text textA" id="question"></textarea>
</div>
<h3>Answer</h3>
<textarea class="answer-text textA" id="answer"></textarea>
<button id="save">Save</button>
<div class="show-error-message hide-error">Please Submit Values</div>
</section>
</article>
<section class="card-container">
</section>
<script src="js/script.js"></script>
</html>
This is a flashcard project I am building. I am fairly new to programming and was looking for help on this particular bug that I cannot wrap my head around. Included in the gist is the css, html, and javascript code. Any tips on code structure is also appreciated.
Question:
When I dynamically create cards using JavaScript I want to show open and close behavior for each of them. The first card created does open and close as expected. However, the following cards do not. For example, one stays open while the other one closes.
I would like each card to open and close independently when clicked after dynamically being created. It seems the behavior is depending on the previous card.
When you call createFlashCard() The html that is generated:
<div class="card-question-button">
<h4 id="title">${questionText}</h4>
<button id="show">></button>
</div>
<div id="answer-card">
<p id="answer-card-p">${answerText}</p>
</div>
These elements will have the same ID's used more than once in a page when they should be unique. Add a unique identifier or remove the id attribute if its not needed. For example:
let cardCount=0;
function createFlashCard() {
cardCount++;
let questionText = document.querySelector('.question-text').value;
let answerText = document.querySelector('.answer-text').value;
let cardSection = document.querySelector('.card-container');
let createArticle = document.createElement('article');
createArticle.className += "card";
let title="title"+ cardCount;
let buttonID="show"+cardCount;
...
<button id=${buttonID}>
...
}
When you are executing your openCloseCards function, you are creating multiple event listeners based on the number of items in buttons.
I'd recommend adding the event listener in your createFlashCard function and removing the function definition of openCloseCards and it's call.
With this change the code seems to working as it should.
function createFlashCard() {
let questionText = document.querySelector('.question-text').value;
let answerText = document.querySelector('.answer-text').value;
let cardSection = document.querySelector('.card-container');
let createArticle = document.createElement('article');
createArticle.className += "card";
createArticle.innerHTML = `
<div class="card-question-button">
<h4 id="title">${questionText}</h4>
<button id="show">></button>
</div>
<div id="answer-card">
<p id="answer-card-p">${answerText}</p>
</div>`;
cardSection.appendChild(createArticle);
createArticle.addEventListener('click', function(e) {
let questions = e.target.parentElement;
questions.classList.toggle("show-text");
console.log(questions.classList)
})
}
So I have a pop up that originally showed on every webpage. After some modification to include the use of cookies to stop the webpage loading every single session, the pop up no longer shows. I can't figure out why and after extensive testing, research and just straight up asking for help I've concluded I do not have enough of an understanding on the subject.
If anyone is able to help me understand why its not working and help with a solution.
<div id='popup' style="display:none">
<div class='cnt223'>
<h1>Important Notice</h1>
<p>
Test!
<br />
<br />
OK
KO
</p>
</div>
</div>
<script>
function setCookie(cname, cvalue) {
window.document.cookie = cname + "=" + cvalue;
}
function getCookie(cname) {
var ca = decodeURIComponent(document.cookie).split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim().split('=');
if (cname == c[0] && c.length > 1) {
return c[1];
}
}
return "";
}
function checkCookie() {
if (getCookie("ageverification") == "") {
$('#popup').show();
$('#popup a.close').click(function ( event ) {
event.preventDefault();
$('#popup').hide();
setCookie("ageverification", 'true');
});
$('#popup a.goBack').click(function ( event ) {
event.preventDefault();
goBack();
});
} else {
return null;
}
}
function goBack() {
window.history.go(-2);
}
checkCookie();
CSS "This is just on the same HTML page for now"
<style type="text/css">
#overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000;
filter:alpha(opacity=70);
-moz-opacity:0.7;
-khtml-opacity: 0.7;
opacity: 0.7;
z-index: 100;
display: none;
}
.cnt223 a{
text-decoration: none;
}
.popup{
width: 100%;
margin: 0 auto;
display: none;
position: fixed;
z-index: 101;
}
.cnt223{
min-width: 600px;
width: 600px;
min-height: 150px;
margin: 100px auto;
background: #f3f3f3;
position: relative;
z-index: 103;
padding: 15px 35px;
border-radius: 5px;
box-shadow: 0 2px 5px #000;
}
.cnt223 p{
clear: both;
color: #555555;
/* text-align: justify; */
font-size: 20px;
font-family: sans-serif;
}
.cnt223 p a{
color: #d91900;
font-weight: bold;
}
.cnt223 .x{
float: right;
height: 35px;
left: 22px;
position: relative;
top: -25px;
width: 34px;
}
.cnt223 .x:hover{
cursor: pointer;
}
</style>
Is the element with id "popup" nested within (a child of) the element with id "overlay" ? If it is, the element with id "overlay" has got display:none; , meaning the popup might be displaying, but it's parent is not. Try replacing:
$('#popup').show();
with:
$('#popup, #overlay').show();
Another problem could be that the Javascript is executed before the browser added the element with id "popup" to it's DOM. Try replacing:
checkCookie();
with:
$(function () { checkCookie(); });