For some reason that I can't figure out, when I add item to my ul dynamically using JS, I get first svg appended under it, like in the picture. Then when I add one more item, second one gets aligned smoothly next to a list item, but there is always this one extra at the bottom and I can't track where is it coming from. Pictures:
<ul id="todo">
<!--<li>Grocery shopping</li>-->
</ul>
<ul id="done"></ul>
ul#todo {
font-family: "Roboto", "sans-serif";
font-size: 20px;
font-weight: 600;
position: relative;
}
ul#done {
position: relative;
}
ul li {
list-style-type: none;
padding-bottom: 10px;
}
.check_mark {
background: url("assets/group.svg");
background-repeat: no-repeat;
float: left;
width: 10%;
height: 20px;
/*position: absolute;
top: 2px;
left: 10px;*/
z-index: 99999;
}
(function () {
var button = document.getElementsByTagName("button");
var userInput = document.getElementById("user_input");
var entered = false;
function addItem() {
if (!entered) {
categorize();
}
var li = document.createElement("li");
li.id = "item";
li.innerHTML = userInput.value;
var item = document.getElementsByTagName("ul")[0].appendChild(li);
var checkMark = document.createElement("div")
checkMark.id = "check_mark";
checkMark.className = "check_mark";
document.getElementsByTagName("ul")[0].appendChild(checkMark);
document.getElementById("item").onclick = function () {
li.remove();
checkMark.remove();
}
checkMark.onclick = function () {
var that = this.parentNode.childNodes[2];
var doneList = document.getElementById("done");
doneList.appendChild(that);
/*this.parentNode.childNodes[2].*/
}
userInput.value = "";
}
function categorize() {
entered = true;
var h1 = document.createElement("h1");
h1.innerHTML = "to-do";
document.getElementById("todo").appendChild(h1);
}
button[0].addEventListener("click", addItem, false);
})();
https://codepen.io/Limpuls/pen/JNbwPE
EDIT:
Alright, so I fixed the problem myself, just changed
document.getElementsByTagName("ul")[0].appendChild(checkMark)
to item.appendChild(checkMark); but now the problem is that when I click a check mark to move the item to another ul list #done, I get error in console
Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'.
at HTMLDivElement.checkMark.onclick (script.js:25)
I just can't figure out why is this hapenning. Any help? Thanks
Related
I'm creating a tab menu like this:
function clear_selected() //sets all columns color black
{
var parent = document.querySelector("#container")
var items = document.querySelectorAll(".item")
var n = items.length;
for (var i = 0; i < n; i++)
items[i].style.backgroundColor = "";
}
function plus(itself) //adds another column
{
var parent = itself.parentElement;
var n = parent.childElementCount;
clear_selected();
var n = parent.querySelectorAll(".item").length;
var page = document.createElement("button");
page.className = "item";
page.style.backgroundColor = "blue";
page.textContent = "column"
page.onclick = function() {
clear_selected();
this.style.backgroundColor = "blue";
};
var temp = document.createElement("span");
temp.className = "del"
temp.innerHTML = "×"
temp.onclick = function() { //it's suppose to remove a column and color default as blue
document.querySelector("#main_item").style.backgroundColor = "blue" //THIS LINE ISN'T WORKING
this.parentElement.remove();
};
page.appendChild(temp);
parent.insertBefore(page, parent.childNodes[n]);
}
function see(el) {
clear_selected();
el.style.backgroundColor = "blue";
}
#container {
display: flex;
width: 100%;
height: 50px;
text-align: center;
background-color: yellow;
}
.item {
background-color: black;
color: white;
border: none;
outline: none;
cursor: pointer;
margin: 0.1rem;
padding: 0.1rem;
max-width: 100%;
}
.del {
background-color: red;
display: inline-block;
cursor: pointer;
border-radius: 50%;
width: 0.7rem;
margin-left: 2rem;
}
<div id="container">
<button class="item" id="main_item" style="background-color:blue;" onclick="see(this)">default column </button>
<button class="item" onclick="plus(this)">+</button>
</div>
but when I press the 'x' to remove a column, I want the default column to color blue, but the line of code which is suppose to achieve that isn't working
document.querySelector("#main_item").style.backgroundColor = "blue"
Before pressing 'x':
After pressing 'x' on the last column:
What it SHOULD look like:
I've losing sleep over this, can someone PLEASE tell me why isn't it working?
When you click on the "X", both of your onclick handlers are getting called, including the one that runs clear_selected, which sets the background color to "".
You can fix this by using stopPropagation on the event passed into the onclick function for the "x". That will stop the click event from going up the chain to the parent element of the "x".
temp.onclick = function(e) {
document.querySelector("#main_item").style.backgroundColor = "blue"
this.parentElement.remove();
e.stopPropagation();
};
My issue is that when i append 2 divs white jQuery, there names are:
This is div 1
This is div 2
But when i remove the first div (This is div 1)
and append another div
it adds one more div whit name (This is div 2):
This is div 2
This is div 2
The reason is because the name of the div counts the total amout of divs... Is there any other way to number all divs so they will always be like this:
This is div 1
This is div 2
This is div 3
Even if i the divs are:
This is div 1
This is div 6
This is div 12
I want them always to be 1,2,3
jQuery code:
$('#add_item').click(function() {
//div count
var countDivs = $("div").length;
//append content
var removeBtn = ('<a class="removeBtn">x</a>')
var h2 = ('<h2>This is div '+countDivs+'</h2>')
var appendContent = ('<div>'+h2+removeBtn+'</div>')
$('#accordion').append(appendContent);
});
//remove button
$(document).on('click', '.removeBtn', function() {
$(this).parent('div').andSelf().remove();
return false;
});
JSFIDDLE
I think you'll have to edit contents of the divs each time a div is removed.
Let's say you have an element and you want to add divs to it.
You will add like you are right now and when you remove you edit all other divs.
The code would be something like this
$('#add_item').click(function() {
var countDivs = $("div").length;
var removeBtn = ('<a class="removeBtn">x</a>')
var h2 = ('<h2>This is div '+countDivs+'</h2>')
var appendContent = ('<div class="appDiv">'+h2+removeBtn+'</div>')
$('#accordion').append(appendContent);
});
$(document).on('click', '.removeBtn', function() {
$(this).parent('div').andSelf().remove();
$('.appDiv').each(function(index,el){
$(el).find('h2').text('This is div '+(index+1));
});
return false;
});
here is the Fiddle
Hope this helps :)
Write a function to renaming the divs and call it after append/remove.
function reArrange() {
$("#accordion > div").each(function(i) {
$(this).find("h2").text("This is div" + (i + 1))
});
}
Fiddle
When an item is removed, change the title of all the elements after it.
$('#add_item').click(function() {
var countDivs = $("#accordion div").length + 1;
var removeBtn = ('<a class="removeBtn">x</a>')
var h2 = ('<h2>This is div <span>' + countDivs + '</span></h2>')
var appendContent = ('<div>' + h2 + removeBtn + '</div>')
$('#accordion').append(appendContent);
});
$(document).on('click', '.removeBtn', function() {
var $div = $(this).parent();
$div.nextAll('div').find('span').html(function(i, html) {
return --html
});
$div.remove();
return false;
});
div {
position: relative;
}
#accordion {
margin-left: 60px;
padding: 10px;
background: #ddd;
}
#add_item {
position: absolute;
top: 20px;
left: 20px;
font-size: 20px;
padding: 5px 10px;
background: black;
color: white;
cursor: pointer;
}
.removeBtn {
font-size: 20px;
padding: 2px 10px 5px;
background: black;
color: white;
cursor: pointer;
position: absolute;
top: 0px;
font-family: verdana;
border-radius: 100%;
left: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="accordion">
</div>
<a id="add_item">+</a>
you should use a global variable like "count":
var count=1;
$('#add_item').click(function() {
//div count
//var countDivs = $("div").length;
var countDivs =count;
//append content
var removeBtn = ('<a class="removeBtn">x</a>')
var h2 = ('<h2>This is div '+countDivs+'</h2>')
var appendContent = ('<div>'+h2+removeBtn+'</div>')
$('#accordion').append(appendContent);
count++;
});
//remove button
$(document).on('click', '.removeBtn', function() {
$(this).parent('div').andSelf().remove();
return false;
});
The easiest update would be to trigger a recount (or other named-event) and, upon addition or removal of an element – by clicking either the #add_item or .removeBtn – call that function using the on() method to listen for that event.
In the below code we bind the event-listener to the #accordion element, as the closest ancestor present in the DOM on page load:
$('#add_item').click(function() {
var removeBtn = ('<a class="removeBtn">x</a>');
var h2 = ('<h2></h2>');
var appendContent = ('<div>'+h2+removeBtn+'</div>');
$('#accordion').append(appendContent).trigger('recount');
});
$(document).on('click', '.removeBtn', function() {
$(this).parent('div').andSelf().remove();
// triggering the 'recount' event from the
// #accordion:
$('#accordion').trigger('recount');
return false;
});
// listening for the 'recount' event:
$('#accordion').on('recount', function(){
// looking within the #accordion for
// the <h2> elements (which contain the
// text to update), and using the text()
// method's anonymous function along with
// its i argument (the index of the current
// <h2> in the collection):
$(this).find('h2').text(function(i){
// returning the text string concatenated
// with the index plus 1 (to get a 1-based
// count, rather than JavaScript's 0-based):
return 'This is div ' + (i + 1);
});
});
$('#add_item').click(function() {
var removeBtn = ('<a class="removeBtn">x</a>');
var h2 = ('<h2></h2>');
var appendContent = ('<div>' + h2 + removeBtn + '</div>');
$('#accordion').append(appendContent).trigger('recount');
});
$(document).on('click', '.removeBtn', function() {
$(this).parent('div').andSelf().remove();
$('#accordion').trigger('recount');
return false;
});
$('#accordion').on('recount', function() {
$(this).find('h2').text(function(i) {
return 'This is div ' + (i + 1);
});
});
div {
position: relative;
}
#accordion {
margin-left: 60px;
padding: 10px;
background: #ddd;
}
#add_item {
position: absolute;
top: 20px;
left: 20px;
font-size: 20px;
padding: 5px 10px;
background: black;
color: white;
cursor: pointer;
}
.removeBtn {
font-size: 20px;
padding: 2px 10px 5px;
background: black;
color: white;
cursor: pointer;
position: absolute;
top: 0px;
font-family: verdana;
border-radius: 100%;
left: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="accordion">
</div>
<a id="add_item">+</a>
References:
on().
text().
trigger().
I'm trying to have a bgcolor change for an element on mouseover, mouseout, and onclick. The problem is Javascript overwrites my onclick with mouseout, so I can't have both. So is there any way to have mouseover reset after mouseout?
function init() {
document.getElementById('default').onmouseover = function() {
tabHoverOn('default', 'grey')
};
document.getElementById('default').onmouseout = function() {
tabHoverOff('default', 'yellow')
};
document.getElementById('section2').onmouseover = function() {
tabHoverOn('section2', 'grey')
};
document.getElementById('section2').onmouseout = function() {
tabHoverOff('section2', 'yellow')
};
document.getElementById('section3').onmouseover = function() {
tabHoverOn('section3', 'grey')
};
document.getElementById('section3').onmouseout = function() {
tabHoverOff('section3', 'yellow')
};
}
function tabHoverOn(id, bgcolor) {
document.getElementById(id).style.backgroundColor = bgcolor;
}
function tabHoverOff(id, bgcolor) {
document.getElementById(id).style.backgroundColor = bgcolor;
}
var current = document.getElementById('default');
function tab1Highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab1highlight";
current = id;
}
function tab2highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab2highlight";
current = id;
}
function tab3highlight(id) {
if (current != null) {
current.className = "";
}
id.className = "tab3highlight";
current = id;
}
window.onload = init();
body {
width: 900px;
margin: 10px auto;
}
nav {
display: block;
width: 80%;
margin: 0 auto;
}
nav > ul {
list-style: none;
}
nav > ul > li {
display: inline-block;
margin: 0 3px;
width: 150px;
}
nav > ul > li > a {
width: 100%;
background-color: #ffff66;
border: 1px solid #9b9b9b;
border-radius: 12px 8px 0 0;
padding: 8px 15px;
text-decoration: none;
font-weight: bold;
font-family: arial, sans-serif;
}
main {
display: block;
width: 80%;
margin: 0 auto;
border: 1px solid #9b9b9b;
padding: 10px;
}
main > h1 {
font-size: 1.5em;
}
.tab1highlight {
background-color: #339966;
color: white;
}
.tab2highlight {
background-color: #ff6666;
color: white;
}
.tab3highlight {
background-color: #6600ff;
color: white;
}
main img {
border: 5px solid #eeefff;
width: 80%;
margin-top: 20px;
}
<body>
<nav>
<ul>
<li>Section 1</li>
<li>Section 2</li>
<li>Section 3</li>
</ul>
</nav>
<main>
<h1>Exercise: Navigation Tab #5</h1>
<ul>
<li>
Combine the navigation tab exercises #1, #3, and #4 in one file, including <br>
<ul>
<li>temporarily change the background color of a tab when the cursor is hovering on it.</li>
<li>set the foreground and background color of the tab being clicked.</li>
<li>change the background color of the main element based on the selected tab.</li>
</ul>
<p>
To test, click on a tab and then move your mouse around. For example, the third tab is clicked, the tab background color is switched to blue. Then hover the mouse over the third tab, the background color of the tab should be switch to light green and then back to blue after the mouse moves out.
</p>
<img src="menu_tab5.jpg">
</li>
</ul>
</main>
It's generally a good idea to keep CSS out of JavaScript completely if you can help it. A better strategy for solving the hover problem is to use the CSS pseudo selector :hover rather than coding the color changes in JavaScript. If you give all your tabs the same class, you only have to write the CSS once:
.tab {
background-color: yellow;
}
.tab:hover {
background-color: grey;
}
Once you've done that, you can also relegate the click styling to CSS by creating an event handler that adds and removes a special class each time a tab is clicked.
In the CSS file:
.tab.clicked {
background-color: blue;
}
And then in JavaScript, something like:
var tabs = document.getElementsByClassName('tab');
for (i = 0; i < tabs.length; i ++) {
tabs[i].onclick = function (ev) {
for (i = 0; i < tabs.length; i ++) {
tabs[i].classList.remove('clicked');
}
ev.currentTarget.classList.add('clicked');
};
}
I've created a JSFiddle to illustrate.
Try updating a Boolean variable.
var Ele = document.getElementById('default');
var clicked = false;
Ele.onclick = function(){
clicked = true;
// add additional functionality here
}
Ele.onmouseover = function(){
clicked = false;
// add additional functionality here
}
Ele.onmouseout = function(){
if(!clicked){
// add additional functionality here
}
}
I am creating 5 new objects of type "RoundDiv" using for loop, it has a property "weirdArray", which is an empty array. Upon calling "init()" method. "someValue" is pushed into the "weirdArray".
The problem is "someValue" is pushed only once each time a new object of type "RounDiv" is created but on clicking any "roundDiv" the console log shows 5 elements in the array, whereas there should be only one.
"use strict";
var roundDivPrototype = {
weirdArray: new Array(),
init: function(label) {
this.weirdArray.push("someValue");
var me = this;
var body = document.body;
var div = document.createElement("div");
div.className = "roundDiv";
div.innerText = label;
div.addEventListener("click", function(e) {
alert("Length of array: " + me.weirdArray.length);
console.log(me.weirdArray); //me=this
});
body.appendChild(div);
}
};
var RoundDiv = function(label) {
this.init(label);
};
RoundDiv.prototype = roundDivPrototype;
for (var i = 0; i < 5; i++) {
new RoundDiv(i);
}
body {
background-color: teal;
text-align: center;
width: 100%;
}
.roundDiv {
display: inline-block;
height: 100px;
width: 100px;
background-color: whitesmoke;
margin: 10px;
border: solid;
border-radius: 50%;
text-align: center;
font-size: 5em;
box-sizing: border-box;
cursor: pointer;
line-height: 100px;
}
<body>
<script src="js/main.js"></script>
</body>
I figured out a possible solution to the problem:
"use strict";
var roundDivPrototype = {
weirdArray: undefined,
init: function(label) {
this.weirdArray = new Array(); //Change in code above
this.weirdArray.push("someValue"); //Change in code above
var me = this;
var body = document.body;
var div = document.createElement("div");
div.className = "roundDiv";
div.innerText = label;
div.addEventListener("click", function(e) {
alert("Length of array: " + me.weirdArray.length); //me=this
console.log(me.weirdArray); //me=this
});
body.appendChild(div);
}
};
var RoundDiv = function(label) {
this.init(label);
};
RoundDiv.prototype = roundDivPrototype;
for (var i = 0; i < 5; i++) {
new RoundDiv(i);
}
body {
background-color: teal;
text-align: center;
width: 100%;
}
.roundDiv {
display: inline-block;
height: 100px;
width: 100px;
background-color: whitesmoke;
margin: 10px;
border: solid;
border-radius: 50%;
text-align: center;
font-size: 5em;
box-sizing: border-box;
cursor: pointer;
line-height: 100px;
}
<body>
<script src="js/main.js"></script>
</body>
Although I figured out a possible solution to the problem but still want to know why previous values in "weirdArray" are present when I'm creating a new object of type "RoundDiv"...
Your contribution is deeply appreciated :)
In your first example, you instantiate weirdArray in the object prototype, making this array property static. Therefore, each of your RoundDiv objects will share the same array to store your data.
Instantiating it in the init function as you do in your second example solves the problem. A new instance of weirdArray will be created each time you create a new RoundDiv.
See this fiddle that shows for each example how many times a new array is created, when, and the array size after each push.
I have seen this code ( http://jsfiddle.net/eMNfd/21/ ), but I want to know how to make the new div can be created to the right of the blue, that is, in horizontal mode.
document.getElementById("text").onclick = function () {
var ok = true;
if (ok === true) {
var div = document.createElement('div');
div.className = 'new-rect';
//div.style.backgroundColor = "black";
document.getElementsByTagName('body')[0].appendChild(div);
}
};
.new-rect {
background: black;
width: 20%;
height: 30px;
}
<div id="text" style="width:20%;height:30px;background-color:blue;"></div>
Thanks to all.
You can use float for this (has to be set on all divs to work), you can also use inline-block:
document.getElementById("text").onclick = function () {
var ok = true;
if (ok === true) {
var div = document.createElement('div');
div.className = 'new-rect';
//div.style.backgroundColor = "black";
document.getElementsByTagName('body')[0].appendChild(div);
}
};
body {
font-size: 0; /* to get rid of the space between the divs */
white-space: nowrap; /* to prevent wrapping on multiple lines */
}
div {
display: inline-block; /* to add divs horizontally */
}
.new-rect {
background: black;
width: 20%;
height: 30px;
}
<div id="text" style="width:20%;height:30px;background-color:blue;"></div>