How to style array elements separately - javascript

I have recently taken up programming and my first task is to create a queue at the post office. The code kind of works and does everything I need, except, I need the input array elements to be displayed with some style, more like separate squares with names (similarly to the way the buttons are styled), not only in line separated by commas - see the demo below please.
var guests = new Array();
for (var i=0;i<10;i++){
guests[i] = prompt("Enter your name");
if (guests[0] == null) {
alert("No guests in a queue");
break;
} else if (guests[i] == null) {
break;
} else {
document.getElementById("queue").innerHTML=guests;
}
}
function removePeople() {
guests.shift();
document.getElementById("queue").innerHTML=guests;
}
function reversePeople() {
guests.reverse();
document.getElementById("queue").innerHTML=guests;
}
button:hover {
background-color:beige;
color:black;
}
.button {
background-color: green;
border: 2px solid black;
border-radius:4px;
color: white;
padding: 5px 15px;
text-align: center;
font-size: 16px;
margin: 4px 2px;
}
<body>
<p id="queue"></p>
<button class="button" onclick ="removePeople()">Next</button>
<button class="button" onclick ="reversePeople()">Reverse</button>
</body>
I tried hard to find some hints here but everything seems too complicated for my level of understanding. So, if there is no easy way, I would rather ask for some specific materials where I could find how to deal with it. I am learning through W3Schools and also reading Eloquent Javascript publication, but coulnd't find anything concerning my problem. I hope my question makes sense.
Also, if you have any idea how to logically improve the code, I am open to any discussion.

I've tried to keep your code mostly the same.
To be able to change the css of a single queue item you need to wrap that item in something (in this example i've used a span)
I've created a function createQueueItemsHtml() that returns the array items wrapped in a span now you can use the following css selector to add css to each item #queue span
var guests = new Array();
for (var i = 0; i < 3; i++) {
var guestInput = prompt("Enter your name");
if(guestInput != "") {
guests[i] = guestInput;
}
if (guests[0] == null) {
alert("No guests in a queue");
break;
} else if (guests[i] == null) {
break;
} else {
document.getElementById("queue").innerHTML = createQueueItemsHtml();
}
}
function removePeople() {
guests.shift();
document.getElementById("queue").innerHTML = createQueueItemsHtml();
}
function reversePeople() {
guests.reverse();
document.getElementById("queue").innerHTML = createQueueItemsHtml();
}
function createQueueItemsHtml() {
let queueString = "";
for (var ii = 0; ii < guests.length; ii++) {
queueString += "<span>" + guests[ii] + "</span>";
}
return queueString;
}
button:hover {
background-color: beige;
color: black;
}
.button {
background-color: green;
border: 2px solid black;
border-radius: 4px;
color: white;
padding: 5px 15px;
text-align: center;
font-size: 16px;
margin: 4px 2px;
}
#queue span {
background-color: green;
border: 2px solid black;
border-radius: 4px;
color: white;
padding: 5px 15px;
}
<p id="queue"></p>
<button class="button" onclick ="removePeople()">Next</button>
<button class="button" onclick ="reversePeople()">Reverse</button>

You can make your guests into <div> elements and then style those in any way you want or need. (I haven't touched the rest of your code, only the part that was needed for this particular thing)
Just change this bit
else {
document.getElementById("queue").innerHTML=guests;
}
To this:
} else {
var guest = document.createElement('div');
guest.classList.add('guest');
guest.innerHTML = guests[i];
document.getElementById("queue").appendChild(guest);
}
What it does is create a <div> element for each item in your guests array, add class="guest" to the element and add the name from your prompt to it. Then it appends this element to the #queue.
Your HTML would then look like this:
<p id="queue">
<div class="guest">john</div>
<div class="guest">doe</div>
</p>
I would suggest changing the <p> to <section> or something like that, just for the sake of semantics.
You can then style these elements like this:
.guest {
}
var guests = new Array();
for (var i=0;i<10;i++){
guests[i] = prompt("Enter your name");
if (guests[0] == null) {
alert("No guests in a queue");
break;
} else if (guests[i] == null) {
break;
} else {
var guest = document.createElement('div');
guest.classList.add('guest');
guest.innerHTML = guests[i];
document.getElementById("queue").appendChild(guest);
}
}
guest:hover {
background-color:beige;
color:black;
}
.guest {
background-color: green;
border: 2px solid black;
border-radius:4px;
color: white;
padding: 5px 15px;
text-align: center;
font-size: 16px;
margin: 4px 2px;
display: inline-block
}
<!DOCTYPE html>
<html>
<head>
<style>
</style>
</head>
<body>
<p id="queue"></p>
</body>
</html>

Related

Failing to get condition to work with div?

I want to have the ball sized to the prompt of the user upon entering it and something doesn't work, can't tell what I'm doing wrong.
<style>
body {
background-color: black;
text-align: center;
}
h1 {
color: white;
}
div {
width: 100px;
height: 100px;
margin: auto;
margin-bottom: 10px;
border-radius: 50%;
transition: 0.3s;
line-height: 50px;
.ball4 {
background-color: brown;
}
</style>
<div class="ball4" onclick="onBall4Click()">
PROMPT
</div>
<script>
function onBall4Click() {
var ball4 = document.querySelector('.ball4');
var ball4Size = prompt("Size of ball? ");
if (ball4Size > 1000) {
alert("Too big!")
} else {
var ball4Size = size;
}
}
</script>
Thanks in advance to the helpers.
I feel like this is what you want with your JavaScript:
function onBall4Click() {
var ball4 = document.querySelector('.ball4');
var ball4Size = prompt("Size of ball? ");
if (ball4Size > 1000) {
alert("Too big!")
} else {
ball4.style.width = ball4Size;
ball4.style.height = ball4Size;
}
}
You were using an undefined variable rather than setting the actual size of the element. Also, I believe you still need to make the element a ball at this point because it is just a brown div right now.

Why the onclick only works if you click twice?

I was searching for autocomplete examples in pure javascript, and I found a pretty good example on JSFiddle, but it has a Bug that I'm trying to figure it out how to fix.
The autocomplete only autocompletes the text if you click at the paragraph twice
Code:
var db = [
"drawLine",
"drawCircle",
"drawCircleMore",
"fillLine",
"fillCircle",
"fillCircleMore"
];
function popupClearAndHide() {
autocomplete_result.innerHTML = "";
autocomplete_result.style.display = "none";
}
function updPopup() {
if (!autocomplete.value) {
popupClearAndHide();
return;
}
var a = new RegExp("^" + autocomplete.value, "i");
for (var x = 0, b = document.createDocumentFragment(), c = false; x < db.length; x++) {
if (a.test(db[x])) {
c = true;
var d = document.createElement("p");
d.innerText = db[x];
d.setAttribute("onclick", "autocomplete.value=this.innerText;autocomplete_result.innerHTML='';autocomplete_result.style.display='none';");
b.appendChild(d);
}
}
if (c == true) {
autocomplete_result.innerHTML = "";
autocomplete_result.style.display = "block";
autocomplete_result.appendChild(b);
return;
}
popupClearAndHide();
}
autocomplete.addEventListener("keyup", updPopup);
autocomplete.addEventListener("change", updPopup);
autocomplete.addEventListener("focus", updPopup);
#autocomplete {
border: 1px solid silver;
outline: none;
margin: 0;
background: #fff;
}
#autocomplete_result {
border: 1px solid silver;
border-top: 0;
position: absolute;
overflow: auto;
max-height: 93px;
background: #fff;
}
#autocomplete,
#autocomplete_result {
width: 200px;
box-sizing: border-box;
}
#autocomplete,
#autocomplete_result p {
padding: 4px;
margin: 0;
color: #000;
}
#autocomplete_result p:nth-child(2n+1) {
background: #f6f6f6;
}
#autocomplete_result p:hover {
background: #e5e5e5;
}
<input id="autocomplete" type="text" />
<div id="autocomplete_result" style="display: none;"></div>
On change event is trigger before the click event can complete
Removing the on change call would fix the issue. Great suggestion from the comment below by 'imvain2' to replace "keyup" event listener with "input" event listener. This would trigger on any input, not only "keyup".
Demo: https://jsfiddle.net/hexzero/qrwgh7pj/
autocomplete.addEventListener("input", updPopup);
autocomplete.addEventListener("focus", updPopup);

Why can't I add a count to my onclick function?

I wanted to try using a count to change the behavior of a click. All my other conditions worked but I don't understand why my count condition doesn't. Does anyone know what I can do to make it work?
For the count I tried -- (this.count == 2), (count == 2), and (uh.count == 2)
function uh() {
var words;
var conf = confirm("ooh that felt goood");
var button = document.querySelector("#selector");
var box =
document.querySelector("#box");
var count = 0;
if (this.count == 5) {
button.classname = "button3";
words = " ";
} else if (this.count == 4) {
button.classname = "button3";
words = "I give up. This is all you get.";
count++;
} else if (this.count == 3) {
button.classname = "button3";
words = "...";
count++;
} else if (this.count == 2) {
button.className = "button2";
words = "the power?";
count++;
} else if (button.className == "button3") {
button.className = "button2";
words = "ahahaha... ha.. uh..";
count++;
} else if (button.className == "button2") {
button.className = "button3";
box.className = "box";
words = "THE POWER";
} else if (conf == true) {
words = "AHAHAHA I HAVE YOU NOW";
button.className = "button2";
} else {
words = "...";
button.className = "button";
}
document.querySelector(".header").innerHTML = words;
}
body {
background-color: black;
}
#header {
text-align: center;
}
.header {
background-color: #000099;
color: white;
display: inline-block;
border: 5px solid white;
padding: 20px;
width: 90%;
}
#box {
text-align: center;
background-color: green;
height: 500px;
}
.box {
text-align: center;
height: 500px;
}
.button {
background-color: grey;
color: white;
margin: 170px;
text-decoration: none;
display: inline-block;
font-size: 20px;
}
.button2 {
background-color: #ff0000;
border: none;
color: white;
padding: 15px 32px;
margin: 170px;
text-decoration: none;
display: inline-block;
font-size: 40px;
box-shadow: 0px 0px 10px white;
}
.button3 {
background-color: black;
border: none;
color: red;
padding: 30px 60px;
margin: 170px;
text-decoration: none;
display: inline-block;
font-size: 60px;
box-shadow: 0px 0px 20px 5px gold;
}
<div id=h eader>
<h1 class="header"> I feel an itch...
<h1>
</div>
<div id="box">
<input type="button" id="selector" class="button" value="CLICK ME" onclick="uh()">
</div>
count is declared and initialized anew each time uh() is called. The variable lifetime ends when the function ends so there is no way to preserve its value across multiple calls to uh().
What you could do, is declare an object called count with a same name property and call() uh on the object. Then this will refer to the object uh() gets called on and thus this.count will have a transferable value across multiple calls on the same object.
var count = {count: 0};
console.log(count.count);//0
up.call(count);
function up() {
this.count++;
//... here add any kind of check on the value of count
}
console.log(count.count);//1

Why Append in JQuery does repeat in span? i want no repeat for tags

i want to no repeat the tags that i will writing in field i try but the console appears the span value repeat like this in image how can i fix that to not repeat the tags. i used JQuery
s://i.stack.imgur.com/dIVP1.jpg
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<input class="add-tags" type="text" placeholder="Type Your Tags">
<div class="tags"></div>
</div>
<script>
$('.add-tags').on('keyup', function(e) {
var tagsKey = e.keyCode || e.which;
if (tagsKey === 188) {
var thisValue = $(this).val().slice(0, -1); //remove last letter
$('.tags').append('<span class="tags-span"><i class="fa fa-times"></i>' + thisValue + '</span>');
var spanvalue = $('.tags-span').text();
console.log(spanvalue);
if (thisValue === spanvalue) {
console.log('good');
} else {
console.log('bad');
}
$(this).val('');
}
$('.tags').on('click', '.tags-span i', function() {
$(this).parent('.tags-span').remove();
});
});
</script>
Voila!
I have a gift for you, but first I would like to point out, that next time you should invest more time into the preparation of your question. Don't cry, don't beg, start from doing your homework first and get as much information as you can. Stackoverflow is not a place were people will do you job for you.
Right now, one can only guess what you are really trying to achieve.
After some harsh treatment let's go to the good parts:
In the following example (https://jsfiddle.net/mkbctrlll/xb6ar2n1/95/)
I have made a simple input that creates a tag on a SPACE key hit. Each tag could be easily removable if X is clicked.
HTML:
<form class="wrapper">
<label for="test">
<span id="tags">
Tags:
</span>
<input id="test" type="text" >
</label>
</form>
JS:
var tagsCollection = []
document.body.onkeyup = function(e){
if(e.keyCode == 32){
var content = getContent('#test')
console.log(tagsCollection.indexOf(content))
if(tagsCollection.indexOf(content) === -1) {
console.log('Spacebar hit! Creating tag')
createTag(content)
tagsCollection.push(content)
console.log(tagsCollection)
} else {
console.log('We already have this one sir!')
displayError('Whoops! Looks like this tag already exists... )')
}
}
}
$('.wrapper').on('click', function(event) {
$(event.target).closest('.tag').remove()
})
function displayError(content) {
var error = document.createElement('p')
error.classList.add('error')
error.innerHTML = content
document.querySelector('.wrapper').append(error)
}
function getContent(target) {
var value = $(target).val().replace(/\W/g, '')
$(target).val("")
return value
}
function createTag(content) {
var $tags = $('#tags')
var tag = document.createElement('span')
var closeIcon = '×'
var iconHTML = document.createElement('span')
iconHTML.classList.add('remove')
iconHTML.innerHTML = closeIcon
tag.classList.add('tag')
tag.append(iconHTML)
tag.append(content)
$tags.append(tag)
}
function removeTag(target) {
target.remove()
}
CSS:
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
.wrapper {
background: #fff;
border-radius: 4px;
padding: 20px;
font-size: 25px;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
}
#tags {
display: block;
margin-bottom: 10px;
font-size: 14px;
}
#test {
display: block;
width: 100%;
}
.tag {
border-radius: 16px;
background-color: #ccc;
color: white;
font-size: 12px;
padding: 4px 6px 4px 16px;
position: relative;
}
.tag:not(:last-child) {
margin-right: 4px;
}
.remove {
font-weight: 600;
position: absolute;
top: 50%;
left: 6px;
cursor: pointer;
transform: translateY(-50%);
}
.remove:hover {
color: red;
}
It is just a quick and dirty example, not a production lvl code.

Sorting an unordered list with JavaScript

I have an unordered list.
This list has elements with checkboxes in it. If you check in a checkbox, the list element goes to the bottom of the list. when you check out one of the checkboxes, it has to go back to its original place. so far, I managed.
BUT. Take the following situation: You checked in all the checkboxes, and they seem to align according to their original place. Now, when you check out a list element, it will stuck between to other elements, which are on their place, but they are checked in. I want that in that case, the checked off box will be the first in the list. Then, when you check off the next box, that one will now be on the right place, aligning with thee unchecked boxes only.
TL;DR:
I have to make a To Do list, the 'done' elements go to the bottom, the undone elements sorted above, according to their timestamp.
http://codepen.io/balazsorban44/pen/mAvqmk
<!DOCTYPE html>
<html>
<head>
<title>A Todo List</title>
<style media="screen">
*{
margin:0;
padding: 0;
font-family: sans-serif;
color: gold;
font-weight: bolder;
font-size: 1em;
border: none;
}
body{
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
width: 100vw;
background: #333;
}
#content{
border: 1px solid #333;
padding: 20px;
border-radius: 10px;
display: flex;
flex-direction: column;
align-items: center;
background-color: gold;
box-shadow: 0px 0px 4px 4px rgba(0,0,0,.2);
}
h1,h2{
display: block;
color: #444;
font-size: 1.3em;
padding: 10px;
align-self: flex-start;
}
h2{
font-size: 1.1em
}
input{
color: #333;
padding: 5px;
border-radius: 5px;
border: 1px solid #333;
box-shadow: inset 0px 0px 3px rgba(0,0,0,.3)
}
input:focus{
outline: none
}
button{
background: #333;
border-radius: 5px;
padding: 5px 10px;
max-width: 50%;
margin-top:15px;
cursor: pointer
}
ul li{
list-style-type: none;
color:#333;
min-width: 100px;
padding: 5px;
align-self: flex-start;
}
ul li input{
margin: 0 5px
}
</style>
</head>
<body onload="loaded()">
<div id=content>
<h1>A very nice To Do list</h1>
<div>
<input id="todo-input" type="text" name="todo-input" value="" placeholder="Click + or press Enter." onkeydown="enter()">
<button type="button" name="button" onclick="addTask()">+</button>
</div>
<h2>Your todo list (done/all): <output>/</output></h2>
<ul id="tasks">
</ul>
</div>
<script type="text/javascript">
const inputArea= document.getElementById('todo-input')
const list = document.getElementById("tasks");
tasks = [];
function loaded(){
inputArea.focus();
}
function addTask(){
const newTask = document.createElement("li")
const text = document.createTextNode(inputArea.value)
const checkBox = document.createElement("input");
newTask.appendChild(text);
list.insertBefore(newTask, list.childNodes[0]);
checkBox.setAttribute("type", "checkbox");
checkBox.setAttribute("onclick", "toggleCheckBox()");
list.childNodes[0].insertBefore(checkBox, list.childNodes[0].childNodes[0]);
tasks.push({timestamp: new Date(), task: inputArea.value});
list.childNodes[0].id=tasks[tasks.length-1].timestamp.getTime();
inputArea.value ="";
inputArea.focus();
}
function enter(){
if(event.keyCode == 13) {
addTask()
}
}
function toggleCheckBox(){
const task = event.target.parentNode
if (task.style.textDecoration == '') {
task.style.textDecoration = 'line-through';
list.appendChild(task)
}
else {
task.style.textDecoration = ''
for (var i = 0; i < tasks.length; i++) {
if (task.id > list.childNodes[i].id) {
list.insertBefore(task, list.childNodes[i]);
break
}
}
}
}
</script>
</body>
</html>
Manage your tasks list in javascript and update the HTML whenever a checkbox value is changed or task is added:
var inputArea = document.getElementById('todo-input')
var list = document.getElementById("tasks");
var tasks = [];
function loaded() {
inputArea.value = "";
inputArea.focus();
}
function update(){
list.innerHTML = '';
// Sort the tasks on done boolean
tasks.sort(function(x, y) {
return (x.done === y.done)? 0 : x.done ? 1 : -1;
});
for(var i = 0; i < tasks.length; i++){
var item = tasks[i];
var task = document.createElement("li")
var text = document.createElement("span");
var checkBox = document.createElement("input");
text.innerHTML = item.task;
text.style.color = 'black';
checkBox.setAttribute("type", "checkbox");
checkBox.addEventListener("change", (function(t){
return function(){
tasks[t].done = this.checked;
console.log(tasks[t]);
update();
}
}(i)));
if(item.done){
checkBox.checked = true;
text.style.textDecoration = 'line-through'
}
task.appendChild(checkBox);
task.appendChild(text);
list.appendChild(task);
}
}
function addTask() {
tasks.push({
id: tasks.length ? tasks[tasks.length - 1].timestamp.getTime() : +new Date(),
done: false,
timestamp: new Date(),
task: inputArea.value
});
update();
loaded();
}
Codepen
I guess you have to make an object structure as
function Task(id,itemName,timeStamp,isCompleted){
this.id=id;
this.itemName=itemName;
this.time=timeStamp;
this.completed=isCompleted;
}
var Tasks=[];
while adding each task,you have to save in such format.
So whenever a task is completed ,you would set completed to true . For all the uncompleted tasks all you need to do is to sort based on their time or based on their name
Hope this helps

Categories