How to change all :root variables with one function - javascript

Similar question : But can't able to get answer
Can be answer to this question : But has to split on each :
If possible to get all variable in one function and change each values
If there are 2-4 variable than easy to change but when that change to 10 or more
var root = document.querySelector(':root');
function func() {
root.style.setProperty('--r', 'brown');
root.style.setProperty('--b', 'lightblue');
root.style.setProperty('--g', 'lightgreen');
}
:root {
--r: red;
--b: blue;
--g: green;
}
.text1 {
color: var(--r)
}
.text2 {
color: var(--b)
}
.text3 {
color: var(--g)
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="func()">Change</button>
Is there a way to automatic(dynamically) get all the variables without writing each variable while values array is self entered
var root = document.querySelector(':root');
var roots = getComputedStyle(root);
var re = roots.getPropertyValue('--r')
var bl = roots.getPropertyValue('--b')
var gr = roots.getPropertyValue('--g')
function func() {
root.style.setProperty('--r', 'brown');
root.style.setProperty('--b', 'lightblue');
root.style.setProperty('--g', 'lightgreen');
}
function func2() {
root.style.setProperty('--r', re);
root.style.setProperty('--b', bl);
root.style.setProperty('--g', gr);
}
:root {
--r: red;
--b: blue;
--g: green;
}
.text1 {
color: var(--r)
}
.text2 {
color: var(--b)
}
.text3 {
color: var(--g)
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="func()">Change</button>
<button onclick="func2()">Orignal</button>
But when getting back to original values then each value is entered by separate variable and for each it is defined .
Is there a way to have a approach which takes original values and variables in separate array automatically.
Thanks for help in advance

I understand you want to first read all the declared variables from the css and store them, so they might be resetted after applying new values?
This code will do this, given that there's just one ':root' declaration in one stylesheet (easily complemented in case 'splitted' declaration in more places needed)
let variableLookup = {
'--r': {
newValue: 'teal'
},
'--b': {
newValue: 'orange'
},
'--g': {
newValue: 'purple'
}
}
var root = document.querySelector(':root');
function setNewColors() {
const cssText = [...document.styleSheets]
.map(styleSheet => [...styleSheet.cssRules]
.filter(CSSStyleRule => CSSStyleRule.selectorText === ':root'))
.flat()[0].cssText
// cssText = ':root { --r: red; --b: blue; --g: green; }'
cssText.match(/{(.*)}/)[1].trim()
.split(';')
.filter(Boolean)
.forEach(declaration => {
const [variable, oldValue] = declaration.split(':').map(str => str.trim())
let entry = variableLookup[variable]
if (entry) entry.oldValue = oldValue
})
console.log('variableLookup >>', variableLookup)
Object.entries(variableLookup).forEach(([variable, {newValue}]) => {
root.style.setProperty(variable, newValue);
})
}
function resetColors() {
Object.entries(variableLookup).forEach(([variable, {oldValue}]) => {
if (oldValue) root.style.setProperty(variable, oldValue)
})
}
:root {
--r: red;
--b: blue;
--g: green;
}
.text1 {
color: var(--r)
}
.text2 {
color: var(--b)
}
.text3 {
color: var(--g)
}
:root {
--c: magenta;
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="setNewColors()">Change to new colors</button>
<button onclick="resetColors()">Reset old colors</button>
Since the OP is interested in a version without using .split() these could be replaced by using a regex and .match()
const declarations = '--r: red; --b: blue; --g: green;'
const regex1 = /^[\w-:\s]+(?=;)|(?<=;)[\w-:\s]+/g
const declarationsArr = declarations.match(regex1)
console.log(declarationsArr) // ["--r: red", " --b: blue", " --g: green"]
const regex2 = /[\w-]+(?=:)|(?<=:\s)[\w-]+/g
const declarationsSplit = declarationsArr.map(d => d.match(regex2))
console.log(declarationsSplit) // [["--r", "red"], ["--b", "blue"], ["--g", "green"]]

One method can be entering all variables and values in different arrays and fetching values from them . Where variables = values which need to be equal have same index number
var root = document.querySelector(':root');
variable = ['--r', '--b', '--g'];
values = ['violet', 'lightblue', 'lightgreen']
function func() {
for (let i = 0; i < 3; i++)
root.style.setProperty(variable[i], values[i]);
}
:root {
--r: red;
--b: blue;
--g: green;
}
.text1 {
color: var(--r)
}
.text2 {
color: var(--b)
}
.text3 {
color: var(--g)
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="func()">Change</button>

const root = document.documentElement;
function changeVariables(...values) {
const variables = ["--r", "--g", "--b"];
for (const variable of variables) {
root.style.setProperty(variable, values[variable.indexof(variables)]);
}
}
//Simply execute function like this
changeVariables("#000", "#808080", "#FF0000");

setting new-colors you want to change
backup original-colors
Try the example bellow
var root = document.querySelector(':root');
var $divEle = $("div[class^='text']"); // get all element with class starting with 'text'
var arrCssVar = ['--r', '--b','--g'];
var backupOrgColor= {}
var newColor = {'--r':'brown', '--b':'lightblue', '--g':'lightgreen'}; // ordering color what you want to change
// backup original colors
$divEle.map(function(i, v) {
if(i < arrCssVar.length){
var compStyle = getComputedStyle(this);
// setting key/value pair to Obj
backupOrgColor[arrCssVar[i]] = compStyle.getPropertyValue(arrCssVar[i]);
}
});
// change color
function setNewColors() {
arrCssVar.map(function (key, value) {
//console.log(key + ": key :change: value : "+ newColor[key]);
root.style.setProperty(key, newColor[key]);
});
}
// reset original color
function resetColors() {
arrCssVar.map(function (key, value) {
//console.log(key + ": key :: value : "+ backupOrgColor[key]);
root.style.setProperty(key, backupOrgColor[key]);
});
}
:root {
--r: red;
--b: blue;
--g: green;
}
.text1 {
color: var(--r)
}
.text2 {
color: var(--b)
}
.text3 {
color: var(--g)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="setNewColors()">Change</button>
<button onclick="resetColors()">Orignal</button>

Try this example.
Initialize two arrays, one is empty for the current colors form the css and second for a new colors.
Need to define how many variables, then get them and put in an empty array.
Create two functions with loops, in the first we assign the new colors for variables, in the second reset.
const root = document.body;
// Colors arrays
const cssVarColors = [];
const newColors = ['brown', 'lightblue', 'lightgreen'];
// Create an array of variable colors from css.
const cssRootArray = document.styleSheets[0].cssRules;
for (const i of cssRootArray) {
// Check, if :root in the css.
if (i.selectorText.includes('root')) {
const rootArrayLength = i.style.length;
for (let j = 0; j < rootArrayLength; j++) {
const key = i.style[j];
// Create object { key/variable : value/color }
const value = getComputedStyle(root).getPropertyValue(key);
cssVarColors.push({[key]: value});
}
}
}
// We change colors, with variable keys and indexes.
function changeColor() {
for (const i in cssVarColors) {
const key = Object.keys(cssVarColors[i]);
// Check, if newColor array don't have a color.
if (!newColors[i]) {
return;
}
root.style.setProperty(key, newColors[i]);
}
variables();
}
change.addEventListener('click', changeColor);
const root = document.body;
// Colors arrays
const cssVarColors = [];
const newColors = ['brown', 'lightblue', 'lightgreen'];
// Create an array of colors from a css variables file.
const cssRootArray = document.styleSheets[0].cssRules;
for (const i of cssRootArray) {
// Check, if :root in the css.
if (i.selectorText.includes('root')) {
const rootArrayLength = i.style.length;
for (let j = 0; j < rootArrayLength; j++) {
const key = i.style[j];
// Create object { key/variable : value/color }
const value = getComputedStyle(root).getPropertyValue(key);
cssVarColors.push({
[key]: value,
});
}
}
}
// We change colors, with variable keys and indexes.
function changeColor() {
for (const i in cssVarColors) {
const key = Object.keys(cssVarColors[i]);
// Check, if newColor array don't have a color.
if (!newColors[i]) {
return;
}
root.style.setProperty(key, newColors[i]);
}
variables();
}
// Can't separate in loop by [key, value],
// because key has a specific value.
function resetColor() {
for (const i in cssVarColors) {
if (!newColors[i]) {
return;
}
const key = Object.keys(cssVarColors[i]);
const value = Object.values(cssVarColors[i]);
root.style.setProperty(key, value);
}
variables();
}
// Change button
change.addEventListener('click', changeColor);
// Reset button
reset.addEventListener('click', resetColor);
// extra for view
cssVarColors.forEach(clr => {
const el = document.createElement('span');
el.textContent = JSON.stringify(clr);
document.getElementById('variables').appendChild(el);
});
:root {
--r: red;
--b: blue;
--g: green;
--m: magenta;
--black: black;
}
.text1 {
color: var(--r);
}
.text2 {
color: var(--b);
}
.text3 {
color: var(--g);
}
/* Extra style */
body {
display: grid;
grid-template-columns: 50px 150px;
grid-template-rows: auto;
}
section {
grid-column: 1;
}
#variables {
grid-column: 2;
display: flex;
flex-direction: column;
}
span:nth-of-type(1) {
border: 5px solid var(--r);
}
span:nth-of-type(2) {
border: 5px solid var(--b);
}
span:nth-of-type(3) {
border: 5px solid var(--g);
}
span:nth-of-type(4) {
border: 5px solid var(--m);
}
span:nth-of-type(5) {
border: 5px solid var(--black);
}
<section>
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
</section>
<div id="variables"></div>
<button id="change">Change</button>
<button id="reset">Reset</button>

Related

How to sort data in javascript?

let div = document.createElement('div');
let ul = document.createElement('ul');
const data = {};
const el = document.getElementById("name");
sortName = 0;
sortCapital = 0;
sortPopulation = 0;
sortArea = 0;
function sortByArea(data) {
var child = container.lastElementChild;
while (child) {
container.removeChild(child);
child = container.lastElementChild;
}
if(sortArea == 0){
data.sort((a, b) => {
if (a.area > b.area) return 1;
else return -1
});
return data;
}
data.sort((a, b) => {
if (a.area < b.area) return 1;
else return -1
});
return data;
}
function sortByPopulation(data) {
var child = container.lastElementChild;
while (child) {
container.removeChild(child);
child = container.lastElementChild;
}
if(sortPopulation == 0){
data.sort((a, b) => {
if (a.population > b.population) return 1;
else return -1
});
return data;
}
data.sort((a, b) => {
if (a.population < b.population) return 1;
else return -1
});
return data;
}
function sortByCapital(data) {
var child = container.lastElementChild;
while (child) {
container.removeChild(child);
child = container.lastElementChild;
}
if(sortCapital == 0){
data.sort((a, b) => {
if (a.capital > b.capital) return 1;
else return -1
});
return data;
}
data.sort((a, b) => {
if (a.capital < b.capital) return 1;
else return -1
});
return data;
}
function sortByName(data) {
var child = container.lastElementChild;
while (child) {
container.removeChild(child);
child = container.lastElementChild;
}
if(sortName == 0){
data.sort((a, b) => {
if (a.name > b.name) return 1;
else return -1
});
return data;
}
data.sort((a, b) => {
if (a.name < b.name) return 1;
else return -1
});
return data;
}
document.getElementById('area').addEventListener('click', () => f(4));
document.getElementById('population').addEventListener('click', () => f(3));
document.getElementById('capital').addEventListener('click', () => f(2));
document.getElementById('name').addEventListener('click', () => f(1));
div.appendChild(ul);
async function f(e) {
//fetching and sorting data by regions and subregions
const res = await fetch("https://restcountries.com/v3.1/all");
var data = await res.json();
const container = document.getElementById('container');
const accordion = document.createElement('div');
const olWrapper = document.getElementById('listWrapper');
const subRegionWrapper = document.getElementById('subRegionWrapper');
switch (e) {
case 1:
data = sortByName(data);
sortName += 1;
sortName %= 2;
case 2:
data = sortByCapital(data);
sortCapital += 1;
sortCapital %= 2;
case 3:
data = sortByPopulation(data);
sortPopulation += 1;
sortPopulation %= 2;
case 4:
data = sortByArea(data);
sortArea += 1;
sortArea %= 2;
}
data.sort((a, b) => {
if (a.region > b.region) return 1;
else if (a.region < b.region) return -1
else {
if (a.subregion > b.subregion) return 1;
else return -1;
}
});
const subRegions = data.reduce((r, a) => {
r[a.subregion] = r[a.subregion] || [];
r[a.subregion].push(a);
return r;
}, {});
const dropdownValues = Object.entries(subRegions);
dropdownValues.forEach(subRegion => {
const accordionWrapper = document.createElement('div');
const panel = document.createElement('div');
panel.classList.add('panel');
accordionWrapper.classList.add('accordion');
const totalArea = subRegion[1].reduce((acc, curr) => acc + curr.area, 0);
const totalPopulation = subRegion[1].reduce((acc, curr) => acc + curr.population, 0);
const li = createSubregion(subRegion[0], totalPopulation, totalArea);
accordionWrapper.appendChild(li);
accordion.appendChild(accordionWrapper);
subRegion[1].forEach(item => {
const subLi = createCountry(item.name.common, item.capital, item.area, item.population);
const subOl = document.createElement('ol');
subOl.appendChild(subLi);
panel.appendChild(subOl);
accordion.appendChild(panel);
});
accordionWrapper.addEventListener('click', function () {
this.classList.toggle("active");
const panel = this.nextElementSibling;
if (panel.style.display === "block") {
panel.style.display = "none";
} else {
panel.style.display = "block";
}
});
});
container.appendChild(accordion);
}
function createSubregion(name, population, area) {
var li = document.createElement("li");
li.setAttribute("class", "subregion");
var header = document.createElement("div");
header.setAttribute("class", "subregion-header disp-flex");
var nameDiv = document.createElement("div");
var nameh2 = document.createElement("h2");
nameh2.innerText = name;
nameDiv.appendChild(nameh2);
header.append(nameDiv);
var emptyDiv = document.createElement("div");
header.appendChild(emptyDiv);
var populationDiv = document.createElement("div");
var populationh2 = document.createElement("h3");
populationh2.innerText = population;
populationDiv.appendChild(populationh2);
header.append(populationDiv);
var areaDiv = document.createElement("div");
var areah2 = document.createElement("h3");
areah2.innerText = area;
areaDiv.appendChild(areah2);
header.append(areaDiv);
li.appendChild(header);
return li;
}
function createCountry(name, capital, area, population) {
var country = document.createElement("li");
country.setAttribute("class", "country disp-flex")
var namediv = document.createElement("div");
var nameh4 = document.createElement("h4");
nameh4.innerText = name;
namediv.appendChild(nameh4);
country.appendChild(namediv);
var capitaldiv = document.createElement("div");
var capitalh4 = document.createElement("h4");
capitalh4.innerText = capital;
capitaldiv.appendChild(capitalh4);
country.appendChild(capitaldiv);
var popdiv = document.createElement("div");
var poph4 = document.createElement("h4");
poph4.innerText = population;
popdiv.appendChild(poph4);
country.appendChild(popdiv);
var areadiv = document.createElement("div");
var areah4 = document.createElement("h4");
areah4.innerText = area;
areadiv.appendChild(areah4);
country.appendChild(areadiv);
return country;
}
f(0);
*{
transition: 500ms;
}
body {
margin: 0 15%;
min-height: 100vh;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: aliceblue;
font-family: 'Open Sans', Arial;
font-size: 18px;
}
#name {
padding: 0 20px;
background-color: rgb(219, 219, 219);
}
#capital {
padding: 0 20px;
background-color: rgb(219, 219, 219);
}
#population {
padding: 0 20px;
background-color: rgb(219, 219, 219);
}
#area {
padding: 0 20px;
background-color: rgb(219, 219, 219);
}
header {
margin: 0 10%;
display: flex;
justify-content: space-between;
padding: 22px 0;
color: rgb(5, 5, 5);
}
ul {
list-style: none;
list-style-type: none;
outline: 2px solid #ddd;
padding: 1rem 2rem;
border-radius: 0.5rem;
list-style-position: inside;
color: blue;
}
ul ol {
color: rgb(197, 105, 18);
list-style: none;
list-style-type: none;
font-size: .9em;
margin: 0.4rem 0;
}
.country {
display: flex;
justify-content: space-between;
}
.disp-flex {
display: flex;
justify-content: space-between;
}
.disp-flex>div {
width: 23%;
padding: 15px 0px;
}
.subregion-header>div:nth-child(1) {
position: relative;
left: 30px;
}
.accordion {
background-color: #eee;
color: #444;
cursor: pointer;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
margin: 15px 2px;
}
.accordion li {
list-style-type: none;
}
.active,
.accordion:hover {
background-color: #ccc;
}
.panel {
margin-left: 5%;
display: none;
background-color: white;
overflow: hidden;
}
#name:hover {
background-color: rgb(114, 114, 114);
cursor: pointer;
}
#capital:hover {
background-color: rgb(114, 114, 114);
cursor: pointer;
}
#population:hover {
background-color: rgb(114, 114, 114);
cursor: pointer;
}
#area:hover {
background-color: rgb(114, 114, 114);
cursor: pointer;
}
<!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>
<main class="container">
<header>
<div id="name">
<h1>Name</h1>
</div>
<div id="capital">
<h1>Capital</h1>
</div>
<div id="population">
<h1>Population</h1>
</div>
<div id="area">
<h1>Area</h1>
</div>
</header>
<div id="container"></div>
<div id="subRegionWrapper"> </div>
<div id="listWrapper"></div>
<script src="script.js"></script>
</main>
</body>
</html>
I made a little data-list containing some information about countries (names, capitals, areas and population), all the countries are grouped by sub-regions. In the header section I have four positions describing each column (name, capital, area and population). I want to add functionality of sorting, so that after clicking on position in the header section, the data would sort by that position. For example after clicking once on name, data should sort by name(asc or desc) and then after clicking once more on name, data should sort inversely to previous sort. I would like to allow sorting by couple columns at same time, so for example after clicking on capital and area, the data should be sorted by capitals and area. Here is my code:
I tried to do that sorting in different ways (adding extra function, passing parameter to main function etc.) but unfortunately nothing worked.I am really struggling with that, I will be extremely grateful for any help.
Your code is actually working, but you are not removing the old table. So the new sorted entries are appended to the already existing ones. You should clear the table some way, for example:
const container = document.getElementById('container');
var child = container.lastElementChild;
while (child) {
container.removeChild(child);
child = container.lastElementChild;
}
Put this where you get the container in your function f(e) and it should be working

Javascript Unable to access global object inside a function in an onclick event

We have the usual example code where everything works.
(myFunction gets triggered on an onclick event.)
"use strict";
console.clear();
const obj = {
name: "falana",
count: 0
};
function myFunction() {
obj.count++;
console.log(obj.count);
console.log(obj.name);
console.log(obj);
}
---Output---
1
"falana"
// [object Object]
{
"name": "falana",
"count": 1
}
From this example, we can access a global object obj inside another function (in this case, myFunction) without any ReferenceError.
I was trying to create a single page Twitter clone (only DOM manipulation) and kept getting this error.
Uncaught ReferenceError: Cannot access 'userData' before initialization at postMessage
---Javascript that's causing error---
window.onload = function() {
console.clear();
}
const userData = {
username: 'Chinmay Ghule',
userhandle: generateUserhandle(this.username),
userPostCount: 0
};
function generateUserhandle(userData) {
const usernameArr = userData.username.split(" ");
usernameArr.forEach(element => {
element.toLowerCase();
});
return "#" + usernameArr.join("");
}
// posts message entered in #message-text to
// message-output-container.
function postMessage() {
console.log(userData);
// get message from #message-text.
const message = document.getElementById('message-text').value;
console.log(`message: ${message}`);
// check for length.
console.log(`message length: ${message.length}`);
if (message.length === 0) {
return;
}
// create new div.
const card = document.createElement('div');
const userInfo = document.createElement('div');
const userMessage = document.createElement('div');
const usernameSpan = document.createElement('span');
const userhandleSpan = document.createElement('span');
const beforeTimeDotSpan = document.createElement('span');
const timeSpan = document.createElement('span');
usernameSpan.classList.add('username');
userhandleSpan.classList.add('userhandle');
beforeTimeDotSpan.classList.add('before-time-dot');
timeSpan.classList.add('time');
userInfo.appendChild(usernameSpan);
userInfo.appendChild(userhandleSpan);
userInfo.appendChild(beforeTimeDotSpan);
userInfo.appendChild(timeSpan);
console.log(`userInfo : ${userInfo}`);
userInfo.classList.add('user-info');
userMessage.classList.add('output-message');
card.appendChild(userInfo);
card.appendChild(userMessage);
console.log(`card : ${card}`);
card.classList.add('output-message');
userMessage.innerText = message;
// check for number of posts.
if (userData.userPostCount === 0) {
let noMessageDiv = document.getElementById("no-message-display");
noMessageDiv.remove();
}
// append new div.
const messageOutputContainer = document.getElementById('message-output-container');
messageOutputContainer.appendChild(card);
// increment userPostCount.
userData.userPostCount++;
}
Why am i getting this ReferenceError in this case, while it didn't in our first example code?
Your code had quite some issues...
The biggest change here was getting rid of generateUserhandle entirely and making it with a getter.
get userhandle() {
return this.username.toLowerCase()
},
Working demo
window.onload = function() {
console.clear();
}
const userData = {
username: 'Chinmay Ghule',
get userhandle() {
return this.username.toLowerCase()
},
userPostCount: 0
};
// posts message entered in #message-text to
// message-output-container.
function postMessage() {
console.log(userData);
// get message from #message-text.
const message = document.getElementById('message-text').value;
console.log(`message: ${message}`);
// check for length.
console.log(`message length: ${message.length}`);
if (message.length === 0) {
return;
}
// create new div.
const card = document.createElement('div');
const userInfo = document.createElement('div');
const userMessage = document.createElement('div');
const usernameSpan = document.createElement('span');
const userhandleSpan = document.createElement('span');
const beforeTimeDotSpan = document.createElement('span');
const timeSpan = document.createElement('span');
usernameSpan.classList.add('username');
userhandleSpan.classList.add('userhandle');
beforeTimeDotSpan.classList.add('before-time-dot');
timeSpan.classList.add('time');
userInfo.appendChild(usernameSpan);
userInfo.appendChild(userhandleSpan);
userInfo.appendChild(beforeTimeDotSpan);
userInfo.appendChild(timeSpan);
console.log(`userInfo : ${userInfo}`);
userInfo.classList.add('user-info');
userMessage.classList.add('output-message');
card.appendChild(userInfo);
card.appendChild(userMessage);
console.log(`card : ${card}`);
card.classList.add('output-message');
userMessage.innerText = message;
// check for number of posts.
if (userData.userPostCount === 0) {
let noMessageDiv = document.getElementById("no-message-display");
noMessageDiv.remove();
}
// append new div.
const messageOutputContainer = document.getElementById('message-output-container');
messageOutputContainer.appendChild(card);
// increment userPostCount.
userData.userPostCount++;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
body {
margin: 0px;
padding: 0px;
font-family: Arial, Helvetica, sans-serif;
}
#container {
/*background-color: lightskyblue;*/
margin: 2.5rem 25%;
}
#user-info {
/*background-color: orange;*/
padding-bottom: 0.5rem;
}
.username {
font-weight: bold;
}
.userhandle,
.before-time-dot,
.time {
opacity: 0.75;
}
#message-text {
width: 100%;
margin-bottom: 0.5rem;
font-size: 18px;
padding: 0.5rem;
resize: none;
border-radius: 0.5rem;
outline: 1px solid lightgray;
}
#message-button {
float: right;
padding: 0.375rem 1.5rem;
font-weight: bold;
font-size: 18px;
border-radius: 1rem;
}
#message-button:hover {
background-color: lightgray;
}
#message-input-container {
background-color: lightskyblue;
padding: 1rem;
border-radius: 0.5rem;
}
#message-input-container::after {
content: "";
clear: both;
display: table;
}
#message-output-container {
/*background-color: lightskyblue;*/
margin-top: 30px;
border-top: 3px solid black;
}
#no-message-display {
text-align: center;
padding: 0.5rem;
}
.output-message {
padding: 0.5rem;
font-size: 18px;
border-bottom: 1px solid lightgray;
}
<div id="container">
<div id="message-input-container">
<textarea id="message-text" rows="5" placeholder="Type your message here..." contenteditable="" value=""></textarea>
<input id="message-button" type="button" value="Post" onclick="postMessage();" />
</div>
<div id="message-output-container">
<div id="no-message-display">
<span>No messages yet!</span>
</div>
</div>
</div>

using JS to make tic tac toe

I have made a tic tac toe using JS however it has some problems My code is:
let x = [];
let o = [];
let xTurn = false;
let winPat = [
['00', '10', '20'],
['01', '11', '21'],
['02', '12', '22'],
['00', '01', '02'],
['10', '11', '12'],
['20', '21', '22'],
['00', '11', '22'],
['02', '11', '20']
];
const tableR = document.getElementsByClassName('tableR');
const button = document.getElementById('btn')
for (let i = 0; i <= 2; i++) {
for (let j = 0; j <= 2; j++) {
let newElement = document.createElement('td');
tableR.item(i).appendChild(newElement);
newElement.addEventListener('click', () => {
if (elementIsEmpty(newElement)) {
const img = document.createElement('img');
if (xTurn) {
img.src = 'https://www.google.com/url?sa=i&url=https%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FFile%3ARed_X.svg&psig=AOvVaw1B-fppvlN2x5oSCGllnXGc&ust=1634565535566000&source=images&cd=vfe&ved=0CAkQjRxqFwoTCMjbg6XN0fMCFQAAAAAdAAAAABAD';
x.push(String(i) + String(j))
} else {
img.src = 'https://www.google.com/imgres?imgurl=https%3A%2F%2Fupload.wikimedia.org%2Fwikipedia%2Fcommons%2Fthumb%2Fd%2Fd0%2FLetter_o.svg%2F407px-Letter_o.svg.png&imgrefurl=https%3A%2F%2Fcommons.wikimedia.org%2Fwiki%2FFile%3ALetter_o.svg&tbnid=p-B77Lz3DDttwM&vet=12ahUKEwizlYTWzdHzAhXMg9gFHTSaBJkQMygAegUIARDaAQ..i&docid=K2HPZsIMOu4d5M&w=407&h=768&q=pixture%20of%20o&ved=2ahUKEwizlYTWzdHzAhXMg9gFHTSaBJkQMygAegUIARDaAQ';
o.push(String(i) + String(j))
}
newElement.append(img)
checkWinOrDraw(xTurn)
xTurn = !xTurn
}
})
}
}
const td = document.getElementsByTagName('td')
button.addEventListener('click', () => {
reset();
});
function elementIsEmpty(el) {
return (/^(\s| )*$/.test(el.innerHTML));
}
function checkWinOrDraw(xTurn) {
for (let i = 0; i < winPat.length; i++) {
if (xTurn) {
if (winPat[i].every(element => x.includes(element))) {
alert('X wins')
reset()
return
}
} else {
if (winPat[i].every(element => o.includes(element))) {
alert('O wins')
reset()
return
}
}
}
for (let item of td) {
if (elementIsEmpty(item))
return
}
alert('Draw')
reset()
}
function reset() {
x = [];
o = [];
for (let item of td) {
item.textContent = ''
}
}
body {
margin: 0px;
background-color: #3c4552;
color: aliceblue;
text-align: center;
}
header {
height: 75px;
background-color: #1f1e1c;
padding: 20px;
font-size: large;
}
table {
border-collapse: collapse;
margin: 40px auto;
}
td {
border: 7px solid black;
height: 121px;
width: 121px;
cursor: pointer;
}
button {
background-color: #1f1e1c;
color: white;
width: 25%;
height: 50px;
font-size: larger;
border: black solid 2px;
border-radius: 7px;
cursor: pointer;
}
img {
display: block;
width: 100%;
height: 100%;
}
<header>
<h1>TicTacToe</h1>
</header>
<main>
<table>
<tr class="tableR"></tr>
<tr class="tableR"></tr>
<tr class="tableR"></tr>
</table>
</main>
<footer>
<button id="btn">RESET</button>
</footer>
my problem is that when the game ends, say X wins, the image is not rendered on the screen, and alert() is called. I googled a lot and found no solutions.
details and clarity:
the image is not rendered on screen at the end of the game. try on your computer and see. alert() is called before the image is present in-game which results in a bad user experience. hence I need a solution.
Here your append() function is not able to complete image load & your checkWinOrDraw() function got called that's why this is happening.
Please try with the below code i am calling the checkWinOrDraw() once image gets loaded or failed.
for (let i = 0; i <= 2; i++) {
for (let j = 0; j <= 2; j++) {
let newElement = document.createElement('td');
tableR.item(i).appendChild(newElement);
newElement.addEventListener('click', () => {
if (elementIsEmpty(newElement)) {
const img = document.createElement('img');
if (xTurn) {
img.src = 'https://dummyimage.com/20x20/3a4ca6/fff';
x.push(String(i) + String(j))
} else {
img.src = 'https://dummyimage.com/30x30/fff/fff';
o.push(String(i) + String(j))
}
console.log(xTurn)
xTurn = !xTurn
img.addEventListener('load', checkWinOrDraw)
img.addEventListener('error', checkWinOrDraw)
newElement.appendChild(img)
}
})
}
}
function checkWinOrDraw(e,xTurn) {
//console.log('checking',xTurn)
for (let i = 0; i < winPat.length; i++) {
if (xTurn) {
if (winPat[i].every(element => x.includes(element))) {
alert('X wins')
reset()
return
}
} else {
if (winPat[i].every(element => o.includes(element))) {
alert('O wins')
reset()
return
}
}
}
for (let item of td) {
if (elementIsEmpty(item))
return
}
alert('Draw')
reset()
}

Show images in quiz javascript

I'm trying to create a quiz that tests users awareness of real and fake emails. What I want to do is have the question displayed at the top saying "Real or Fake", then have an image displayed underneath which the user needs to look at to decided if it's real or fake. There are two buttons, real and fake, and regardless of whether they choose the right answer I want to swap the original image with annotated version - showing how users could spot that it was fake or real.
But I'm not sure how to show the annotated version once the answer has been submitted. Could someone help?
function Quiz(questions) {
this.score = 0;
this.questions = questions;
this.questionIndex = 0;
}
Quiz.prototype.getQuestionIndex = function() {
return this.questions[this.questionIndex];
}
Quiz.prototype.guess = function(answer) {
if (this.getQuestionIndex().isCorrectAnswer(answer)) {
this.score++;
}
this.questionIndex++;
}
Quiz.prototype.isEnded = function() {
return this.questionIndex === this.questions.length;
}
function Question(text, choices, answer) {
this.text = text;
this.choices = choices;
this.answer = answer;
}
Question.prototype.isCorrectAnswer = function(choice) {
return this.answer === choice;
}
function populate() {
if (quiz.isEnded()) {
showScores();
} else {
// show question
var element = document.getElementById("question");
element.innerHTML = quiz.getQuestionIndex().text;
// show options
var choices = quiz.getQuestionIndex().choices;
for (var i = 0; i < choices.length; i++) {
var element = document.getElementById("choice" + i);
element.innerHTML = choices[i];
guess("btn" + i, choices[i]);
}
showProgress();
}
};
function guess(id, guess) {
var button = document.getElementById(id);
button.onclick = function() {
quiz.guess(guess);
populate();
}
};
function showProgress() {
var currentQuestionNumber = quiz.questionIndex + 1;
var element = document.getElementById("progress");
element.innerHTML = "Question " + currentQuestionNumber + " of " + quiz.questions.length;
};
function showScores() {
var gameOverHTML = "<h1>Result</h1>";
gameOverHTML += "<h2 id='score'> Your scores: " + quiz.score + "</h2>";
var element = document.getElementById("quiz");
element.innerHTML = gameOverHTML;
};
// create questions here
var questions = [
new Question("<img src= 'netflix_fake.jpg' />", ["Real", "Fake"], "Fake"),
new Question("<img src= 'dropbox_real.jpg' />", ["Real", "Fake"], "Real"),
new Question("<img src= 'gov_real.jpg' />", ["Real", "Fake"], "Real"),
new Question("<img src= 'paypal_fake.jpg' />", ["Real", "Fake"], "Fake"),
new Question("<img src= 'gmail.jpg' />", ["Real", "Fake"], "Fake")
];
//create quiz
var quiz = new Quiz(questions);
// display
populate();
body {
background-color: #538a70;
}
.grid {
width: 600px;
height: 500px;
margin: 0 auto;
background-color: #fff;
padding: 10px 50px 50px 50px;
border: 2px solid #cbcbcb;
}
.grid h1 {
font-family: "sans-serif";
font-size: 60px;
text-align: center;
color: #000000;
padding: 2px 0px;
}
#score {
color: #000000;
text-align: center;
font-size: 30px;
}
.grid #question {
font-family: "monospace";
font-size: 30px;
color: #000000;
}
.buttons {
margin-top: 30px;
}
#btn0,
#btn1,
#btn2,
#btn3 {
background-color: #a0a0a0;
width: 250px;
font-size: 20px;
color: #fff;
border: 1px solid #1D3C6A;
margin: 10px 40px 10px 0px;
padding: 10px 10px;
}
#btn0:hover,
#btn1:hover,
#btn2:hover,
#btn3:hover {
cursor: pointer;
background-color: #00994d;
}
#btn0:focus,
#btn1:focus,
#btn2:focus,
#btn3:focus {
outline: 0;
}
#progress {
color: #2b2b2b;
font-size: 18px;
}
<div class="grid">
<div id="quiz">
<h1>Can you spot the fake email?</h1>
<hr style="margin-bottom: 20px">
<p id="question"></p>
<div class="buttons">
<button id="btn0"><span id="choice0"></span></button>
<button id="btn1"><span id="choice1"></span></button>
</div>
<hr style="margin-top: 50px">
<footer>
<p id="progress">Question x of y</p>
</footer>
</div>
</div>
When user clicks button I trigger class and I add it second name, on second I have written to get swapped, I wrote you basically full project, and please read the whole comments, to understand logic
//Calling Elements from DOM
const button = document.querySelectorAll(".check");
const images = document.querySelectorAll(".image");
const answer = document.querySelector("h1");
//Declaring variable to randomly insert any object there to insert source in DOM Image sources
let PreparedPhotos;
//Our Images Sources and With them are its fake or not
//fake: true - yes its fake
//fake: false - no its real
const image = [
[
{
src:
"https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/1200px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg",
fake: true
},
{
src:
"http://graphics8.nytimes.com/images/2012/04/13/world/europe/mona-lisa-like-new-images/mona-lisa-like-new-images-custom4-v3.jpg",
fake: false
}
],
[
{
src:
"https://cdn.shopify.com/s/files/1/0849/4704/files/Creacion_de_Adan__Miguel_Angel_f5adb235-bfa8-4caa-8ffb-c5328cbad953_grande.jpg?12799626327330268216",
fake: false
},
{
src:
"https://cdn.shopify.com/s/files/1/0849/4704/files/First-image_Fb-size_grande.jpg?10773543754915177139",
fake: true
}
]
];
//Genrating Random Photo on HTML
function setRandomPhoto() {
//Random Number which will be length of our array of Object
//if you array includes 20 object it will generate random number
// 0 - 19
const randomNumber = Math.floor(Math.random() * image.length);
//Decalaring our already set variable as Array Object
PreparedPhoto = image[randomNumber];
//Our first DOM Image is Variables first object source
images[0].src = PreparedPhoto[0].src;
//and next image is next object source
images[1].src = PreparedPhoto[1].src;
}
//when windows successfully loads, up function runs
window.addEventListener("load", () => {
setRandomPhoto();
});
//buttons click
//forEach is High Order method, basically this is for Loop but when you want to
//trigger click use forEach - (e) is single button whic will be clicked
button.forEach((e) => {
e.addEventListener("click", () => {
//decalring variable before using it
let filtered;
//finding from our DOM image source if in our long array exists
//same string or not as Image.src
//if it exists filtered variable get declared with that found obect
for (let i = 0; i < image.length; i++) {
for (let k = 0; k < 2; k++) {
if (image[i][k].src === images[0].src) {
filtered = image[i][k];
}
}
}
//basic if else statement, if clicked button is Fake and image is true
//it outputs You are correct
//if clicked button is Real and Image is false it outputs Correct
//Else its false
//Our image checking comes from filtered variable
if (e.innerText === "Fake" && filtered.fake === true) {
answer.innerText = "You Are Correct";
images.forEach((image) => {
image.classList.toggle("hidden");
});
} else if (e.innerText === "Real" && filtered.fake === false) {
answer.innerText = "You Are Correct";
images.forEach((image) => {
image.classList.toggle("hidden");
});
} else {
answer.innerHTML = "You are Wrong";
images.forEach((image) => {
image.classList.toggle("hidden");
});
}
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100%;
min-height: 100vh;
display: flex;
justify-content: space-around;
align-items: center;
flex-direction: column;
}
.image-fluid {
display: flex;
}
.image-fluid .image {
width: 200px;
margin: 0 10px;
transition: 0.5s;
}
.image-fluid .image:nth-child(1).hidden {
transform: translateX(110px);
}
.image-fluid .image:nth-child(2).hidden {
transform: translateX(-110px);
}
<div class="container">
<div class="image-fluid">
<img src="" class="image hidden">
<img src="" class="image hidden">
</div>
<div class="button-fluid">
<button class="check">Fake</button>
<button class="check">Real</button>
</div>
</div>
<h1></h1>

Avoid duplicates from random selection

This code fetches multiple words from the same arrays of words and parse it into HTML. Inside the get_word function, how can I avoid the same word from being selected and printed multiple times?
NO: Car, Car, House, Cat
YES: Car, Dog, House, Cat
var words = ["Buss", "Plane", "Car","Dog","Cat", "House"];
get_random = function (list) {
return list[Math.floor((Math.random()*list.length))];
}
get_word = function (number) {
for (i = 1; i < number+1; i++) {
word = get_random(words);
document.getElementById("word"+i).innerHTML = word;
}
}
start = function () {
get_word(3);
}
div.buttons {
text-align: center;
margin: 15px;
}
.button {
background-color: #4CAF50;
/* Green */
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
}
#word1,
#word2,
#word3,
#word4 {
text-align: center;
font-size: 48px;
color: red;
bottom: 15px;
}
<div id="word1"></div>
<div id="word2"></div>
<div id="word3"></div>
<div id="word4"></div>
<div class="buttons">
<button class="button" onclick="start();">Try it</button>
</div>
I aggree with hoangdv but it can be event simpler
const words = ["Bus", "Plane", "Car","Dog","Cat", "House"];
function shuffle(array) {
array.sort(() => Math.random() - 0.5);
return array
}
get_word = function (number) {
return shuffle(words).slice(0,number)
}
console.log(get_word(3))
console.log(get_word(3))
console.log(get_word(3))
I think the solution to your problem is using pop(), although you will need to make sure that you keep a copy of your original list somewhere if you need to reference it later, as pop will change the list and reduce its length.
This means your function get_random should look closer to:
get_random = function (list)
{
return list.pop(Math.floor((Math.random()*list.length)))
}
I think you can shuffle the array then get get each item of the the shuffled array.
function shuffle(array) {
array.sort(() => Math.random() - 0.5);
}
get_word = function (number) {
shuffle(words);
for (i = 1; i < number+1; i++) {
word = words[i - 1];
document.getElementById("word"+i).innerHTML = word;
}
}
Add an extra variable can resolve the issue.
get_word = function (number) {
var out = [];
for (i = 1; i < number+1; i++) {
word = get_random(words);
if(out.findIndex(w=>w==word) > -1){
out.push(word);
document.getElementById("word"+i).innerHTML = word;
}
}
}

Categories