I have a favourites feature, but want the user to be able to remove them.
This is what it looks like:
So what I want to achieve is a "Remove" link under each item which calls the remove function, and so removes that entity.
Here is my JS:
function updateFavourite(video) {
document.getElementById('favourite').onclick = function () {
if ($.grep(myfavourite, function (item) {
return item["id"] == video["id"];
}).length == 0) {
blacklist[video["id"]] = true;
myfavourite.push(video);
var html = "<li class=\"history\">" +
"<img class= \"img-rounded\" src=\"{0}\"/>" +
"<p><b title=\"{2}\"><a class=\"extendedLink\" href=\"javascript:watchFavouriteVideo(\'{1}\');\"><span></span>{2}</a></b><br>" +
"by {3}<br>" +
"{4} | {5} views</p>" +
"</li>";
$("#myfavourite").prepend(html.format(video["thumbnail"],
video["id"],
video["title"],
video["uploader"],
video["length"],
video["views"]));
}
}
}
function remove(video) {
document.getElementById('remove').onclick = function () {
myfavourite.splice(video, 1);
}
}
The problem is that it does not remove the video, and don't know how to add the "Remove" text for each entity.
Here is an example
HTML
<div id="favourites"></div>
<div id="displayList"></div>
CSS
#favourites {
width:auto;
height:100px;
}
.favourite {
width:auto;
height: auto;
margin-right:10px;
background-color:cyan;
float:left;
}
.title {
width:auto;
height: auto;
background-color:red;
border:0px;
text-align:center;
}
.picture {
width:50px;
height: 50px;
background-position:center;
display:block;
margin:0 auto;
}
.remove {
width:auto;
height: auto;
text-align:center;
}
.remove:hover {
cursor:pointer;
background-color:yellow;
}
#displayList {
min-height:20px;
clear:both;
border:1px solid black;
}
Javascript
var picsArray = [
'http://upload.wikimedia.org/wikipedia/commons/1/1b/Beys_Afroyim_with_son_%28cropped%29.jpg',
'http://upload.wikimedia.org/wikipedia/commons/8/8a/Tammam_Salam.jpg',
'http://upload.wikimedia.org/wikipedia/commons/2/27/Ratusz2007.jpg',
'http://upload.wikimedia.org/wikipedia/commons/6/60/GPN-2000-001979.jpg'
],
list = picsArray.slice(),
favourites = document.getElementById('favourites'),
displayList = document.getElementById('displayList');
function emptyNode(node) {
while (node.firstChild) {
node.removeChild(node.firstChild);
}
}
function updateDisplayList() {
emptyNode(displayList);
list.map(function (entry) {
return entry.split('/').slice(-1)[0];
}).forEach(function (shortEntry) {
var p = document.createElement('p');
p.appendChild(document.createTextNode(shortEntry));
displayList.appendChild(p);
});
}
list.forEach(function (pic) {
var favourite = document.createElement('div'),
title = document.createElement('div'),
img = document.createElement('img'),
remove = document.createElement('div');
favourite.className = 'favourite';
title.className = 'title';
img.className = 'picture';
remove.className = 'remove';
title.appendChild(document.createTextNode('Favourite'));
favourite.appendChild(title);
img.src = pic;
favourite.appendChild(img);
remove.appendChild(document.createTextNode('Remove'));
remove.addEventListener('click', function (e) {
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
list = list.filter(function (ele) {
return ele !== e.target.previousSibling.src;
});
updateDisplayList();
}, false);
favourite.appendChild(remove);
favourites.appendChild(favourite);
});
updateDisplayList();
On jsFiddle
Related
Below I have a simplified version of my code where I can click a button to add new elements. These element should all be draggable so they can swap places and they should also have functionality to be deleted when clicking somewhere on them. I have implemented this successfully as you can see by running my snippet ... except for one thing ...
If you try to click on the button area in the middle before swapping it with anything it works just like I want it to.
But if you try to click on it after you have swapped it, it no longer works. Please help me fix this!
const btn_add_element = document.querySelector('.btn_add_element');
const my_draggable_elements = document.querySelector('.my_draggable_elements');
function handleDragStart(e) {
this.style.opacity = '0.4';
dragSrcEl = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
}
function handleDragEnd(e) {
this.style.opacity = '1'; my_draggable_elements.querySelectorAll('.container').forEach(elm => {
elm.classList.remove('dragged_over');
});
}
function handleDragOver(e) {
e.preventDefault();
return false;
}
function handleDragEnter(e) {
this.classList.add('dragged_over');
}
function handleDragLeave(e) {
this.classList.remove('dragged_over');
}
function handleDrop(e) {
e.stopPropagation();
if (dragSrcEl !== this) {
dragSrcEl.innerHTML = this.innerHTML;
this.innerHTML = e.dataTransfer.getData('text/html');
}
return false;
}
function getRandomColor() { return '#'+Math.floor(Math.random()*16777215).toString(16); }
function add_element() {
// Create Container & Make it draggable
const new_container = document.createElement('div');
new_container.classList.add('container');
new_container.setAttribute('draggable', true);
new_container.addEventListener('dragstart', handleDragStart);
new_container.addEventListener('dragover', handleDragOver);
new_container.addEventListener('dragenter', handleDragEnter);
new_container.addEventListener('dragleave', handleDragLeave);
new_container.addEventListener('dragend', handleDragEnd);
new_container.addEventListener('drop', handleDrop);
// Create Content
const new_content = document.createElement('div');
new_content.classList.add('content');
new_content.style.color = getRandomColor();
new_content.innerText = 'Click to Delete';
new_content.addEventListener('click', () => {
new_container.remove();
});
new_container.appendChild(new_content);
my_draggable_elements.appendChild(new_container);
}
btn_add_element.addEventListener('click', () => add_element());
btn_add_element.click();
btn_add_element.click();
btn_add_element.click();
.my_draggable_elements {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.container {
padding: 2rem;
border: 0.1rem solid black;
cursor: grab;
}
.container.dragged_over {
border: 0.1rem dashed black;
}
.container > .content {
background-color: #ddd;
padding: 0.25rem;
cursor: pointer;
}
.btn_add_element {
margin-top: 2rem;
width: 100%;
text-align: center;
padding: 0.5rem;
}
<div class='my_draggable_elements'></div>
<button class='btn_add_element'>Add Element</button>
In handleDrop() the element get's transfered from event.dataTransfer.getData('text/html') to the innerHTML of the element it is being dropped on. In that, the eventListener is lost. You have to add it again, as demonstrated in the modified snippet below.
const btn_add_element = document.querySelector('.btn_add_element');
const my_draggable_elements = document.querySelector('.my_draggable_elements');
function handleDragStart(e) {
this.style.opacity = '0.4';
dragSrcEl = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
}
function handleDragEnd(e) {
this.style.opacity = '1'; my_draggable_elements.querySelectorAll('.container').forEach(elm => {
elm.classList.remove('dragged_over');
});
}
function handleDragOver(e) {
e.preventDefault();
return false;
}
function handleDragEnter(e) {
this.classList.add('dragged_over');
}
function handleDragLeave(e) {
this.classList.remove('dragged_over');
}
function handleDrop(e) {
e.stopPropagation();
if (dragSrcEl !== this) {
dragSrcEl.innerHTML = this.innerHTML;
console.log(this.innerHTML);
this.innerHTML = e.dataTransfer.getData('text/html');
this.addEventListener('click', () => {
this.remove();
});
}
return false;
}
function getRandomColor() { return '#'+Math.floor(Math.random()*16777215).toString(16); }
function add_element() {
// Create Container & Make it draggable
const new_container = document.createElement('div');
new_container.classList.add('container');
new_container.setAttribute('draggable', true);
new_container.addEventListener('dragstart', handleDragStart);
new_container.addEventListener('dragover', handleDragOver);
new_container.addEventListener('dragenter', handleDragEnter);
new_container.addEventListener('dragleave', handleDragLeave);
new_container.addEventListener('dragend', handleDragEnd);
new_container.addEventListener('drop', handleDrop);
// Create Content
const new_content = document.createElement('div');
new_content.classList.add('content');
new_content.style.color = getRandomColor();
new_content.innerText = 'Click to Delete';
new_content.addEventListener('click', () => {
new_container.remove();
});
new_container.appendChild(new_content);
my_draggable_elements.appendChild(new_container);
}
btn_add_element.addEventListener('click', () => add_element());
btn_add_element.click();
btn_add_element.click();
btn_add_element.click();
.my_draggable_elements {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.container {
padding: 2rem;
border: 0.1rem solid black;
cursor: grab;
}
.container.dragged_over {
border: 0.1rem dashed black;
}
.container > .content {
background-color: #ddd;
padding: 0.25rem;
cursor: pointer;
}
.btn_add_element {
margin-top: 2rem;
width: 100%;
text-align: center;
padding: 0.5rem;
}
<div class='my_draggable_elements'></div>
<button class='btn_add_element'>Add Element</button>
With the help of #anarchist912, I finally got the desired result.
As he stated in his answer, the eventlistener for removing the element gets lost inside the handleDrop function. To fix this we had to manually add the eventlistener back again.
this.addEventListener('click', () => {
this.remove();
});
However this was apparently not enough.
I accidentally solved this by writing a remove_element() function for my personal use-case and getting it to work, then realising it was not working here when I tested it in the snippet using the arrow function like above. So here are the changes that made it work:
function remove_element(e) {
e.target.closest('.container').remove();
}
// and inside handleDrop()
dragSrcEl.querySelector('.content').addEventListener('click', remove_element);
this.querySelector('.content').addEventListener('click', remove_element);
const btn_add_element = document.querySelector('.btn_add_element');
const my_draggable_elements = document.querySelector('.my_draggable_elements');
function handleDragStart(e) {
this.style.opacity = '0.4';
dragSrcEl = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
}
function handleDragEnd(e) {
this.style.opacity = '1'; my_draggable_elements.querySelectorAll('.container').forEach(elm => {
elm.classList.remove('dragged_over');
});
}
function handleDragOver(e) {
e.preventDefault();
return false;
}
function handleDragEnter(e) {
this.classList.add('dragged_over');
}
function handleDragLeave(e) {
this.classList.remove('dragged_over');
}
function handleDrop(e) {
e.stopPropagation();
if (dragSrcEl !== this) {
dragSrcEl.innerHTML = this.innerHTML;
dragSrcEl.querySelector('.content').addEventListener('click', remove_element);
this.innerHTML = e.dataTransfer.getData('text/html');
this.querySelector('.content').addEventListener('click', remove_element);
}
return false;
}
function getRandomColor() { return '#'+Math.floor(Math.random()*16777215).toString(16); }
function remove_element(e) {
e.target.closest('.container').remove();
}
function add_element() {
// Create Container & Make it draggable
const new_container = document.createElement('div');
new_container.classList.add('container');
new_container.setAttribute('draggable', true);
new_container.addEventListener('dragstart', handleDragStart);
new_container.addEventListener('dragover', handleDragOver);
new_container.addEventListener('dragenter', handleDragEnter);
new_container.addEventListener('dragleave', handleDragLeave);
new_container.addEventListener('dragend', handleDragEnd);
new_container.addEventListener('drop', handleDrop);
// Create Content
const new_content = document.createElement('div');
new_content.classList.add('content');
new_content.style.color = getRandomColor();
new_content.innerText = 'Click to Delete';
new_content.addEventListener('click', remove_element);
new_container.appendChild(new_content);
my_draggable_elements.appendChild(new_container);
}
btn_add_element.addEventListener('click', () => add_element());
btn_add_element.click();
btn_add_element.click();
btn_add_element.click();
.my_draggable_elements {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.container {
padding: 2rem;
border: 0.1rem solid black;
cursor: grab;
}
.container.dragged_over {
border: 0.1rem dashed black;
}
.container > .content {
background-color: #ddd;
padding: 0.25rem;
cursor: pointer;
}
.btn_add_element {
margin-top: 2rem;
width: 100%;
text-align: center;
padding: 0.5rem;
}
<div class='my_draggable_elements'></div>
<button class='btn_add_element'>Add Element</button>
I am trying to make a simple search function with just javascript but for some reason which I cant figure out it doesnt show me anything when I enter something into my Searchbar. Thanks in advance. Here is the Code:
var terms = new Array();
var max = 6;
for (i=1;i<=max;i++) {
terms[i] = new Array();
}
terms[1]['search'] = 'google internet search web';
terms[1]['des'] = 'Google search';
terms[1]['lnk'] = 'http://www.google.com';
terms[2]['search'] = 'gmx mail email';
terms[2]['des'] = 'GMX Mail';
terms[2]['lnk'] = 'http://www.gmx.com';
terms[3]['search'] = 'web mail email';
terms[3]['des'] = 'Web Mail';
terms[3]['lnk'] = 'http://www.web.com';
terms[4]['search'] = 'youtube video your self';
terms[4]['des'] = 'Youtube Video';
terms[4]['lnk'] = 'http://www.youtube.com';
terms[5]['search'] = 'wikipedia search knowledge';
terms[5]['des'] = 'Wikipedia';
terms[5]['lnk'] = 'http://www.wikipedia.com';
terms[6]['search'] = 'facebook social';
terms[6]['des'] = 'Facebook';
terms[6]['lnk'] = 'https://www.facebook.com';
function search() {
var input = document.getElementById('searchbar').value.toLowerCase();
var i=0;
var list="";
var pos=-1;
if(input!="") {
for(i=1; i<=max; i++) {
pos= terms[i]['search'].indexOf(input);
if(pos!=-1) {
list= list + '<a class="search_lnk" href="' + terms[i]['des'] + '</a>' + '<br>';
}
pos=-1;
}
if(list==""){
document.getElementById("listing").innerHTML = "";
document.getElementById("listing").style.display = "none";
} else {
document.getElementById("listing").innerHTML = list;
document.getElementById("listing").style.display = "block";
}
}
}
.cont_ges {
border: 1px dotted #0080FF;
border-radius:10px;
position:absolute;
width:220px;
height:46px;
left:50%;
top:50%;
margin-left:-110px;
margin-top:-23px;
}
.ubers {
font-size:18px;
color:#800080;
font-weight:bold;
font-style:italic;
text-align:center;
position:absolute;
width 100%;
height:22px;
left:0px;
top:0px;
margin-top:-25px;
}
.such_lnk {
font-size:16px;
color:#FF8000;
font-style:italic;
text-decoration: none;
}
.suche_lnk a:hover {
color:#FFFF00;
text-decoration: underline;
z-index:10;
}
#listing {
position:absolute;
left:5px;
top:35px;
width: 120%;
overflow:auto;
}
#searchbar{
position:absolute;
left:5px;
width:90%;
}
<div class="cont_ges">
<span class="ubers">Enter</span>
<input id="searchbar" type="text" value="Search.." onClick="this.value='';" onKeyup="search();">
<div id="listing"></div>
</div>
Please correct your search function:
function search() {
var input = document.getElementById('searchbar').value.toLowerCase();
var i=0;
var list="";
var pos=-1;
if(input!="") {
for(i=1; i<=max; i++) {
pos= terms[i]['search'].indexOf(input);
if(pos!=-1) {
// You have error in this line
list= list + '<a class="search_lnk" href="'+terms[i]['lnk']+'">' + terms[i]['des'] + '</a>' + '<br>';
}
pos=-1;
}
if(list==""){
document.getElementById("listing").innerHTML = "";
document.getElementById("listing").style.display = "none";
} else {
document.getElementById("listing").innerHTML = list;
document.getElementById("listing").style.display = "block";
}
}
}
Working demo.
Just correct this line, it will work as expected ( for some reason it will not run here correctly in the test console of SO, but its working fine on html page)
if(pos!=-1) {
list= list + '<a class="search_lnk" href="' + terms[i]['des']+ '">'+terms[i]['des']+ '</a>' + '<br>';
}
var terms = new Array();
var max = 6;
for (i=1;i<=max;i++) {
terms[i] = new Array();
}
terms[1]['search'] = 'google internet search web';
terms[1]['des'] = 'Google search';
terms[1]['lnk'] = 'http://www.google.com';
terms[2]['search'] = 'gmx mail email';
terms[2]['des'] = 'GMX Mail';
terms[2]['lnk'] = 'http://www.gmx.com';
terms[3]['search'] = 'web mail email';
terms[3]['des'] = 'Web Mail';
terms[3]['lnk'] = 'http://www.web.com';
terms[4]['search'] = 'youtube video your self';
terms[4]['des'] = 'Youtube Video';
terms[4]['lnk'] = 'http://www.youtube.com';
terms[5]['search'] = 'wikipedia search knowledge';
terms[5]['des'] = 'Wikipedia';
terms[5]['lnk'] = 'http://www.wikipedia.com';
terms[6]['search'] = 'facebook social';
terms[6]['des'] = 'Facebook';
terms[6]['lnk'] = 'https://www.facebook.com';
function search() {
var input = document.getElementById('searchbar').value.toLowerCase();
var i=0;
var list="";
var pos=-1;
if(input!="") {
for(i=1; i<=max; i++) {
pos= terms[i]['search'].indexOf(input);
console.log(terms[i]['search']+pos);
if(pos!=-1) {
list= list + '<a class="search_lnk" href="' + terms[i]['des']+ '">'+terms[i]['des']+ '</a>' + '<br>';
}
pos=-1;
}
console.log(list);
if(list==""){
document.getElementById("listing").innerHTML = "";
document.getElementById("listing").style.display = "none";
} else {
document.getElementById("listing").innerHTML = list;
document.getElementById("listing").style.display = "block";
}
}
}
.cont_ges {
border: 1px dotted #0080FF;
border-radius:10px;
position:absolute;
width:220px;
height:46px;
left:50%;
top:50%;
margin-left:-110px;
margin-top:-23px;
}
.ubers {
font-size:18px;
color:#800080;
font-weight:bold;
font-style:italic;
text-align:center;
position:absolute;
width 100%;
height:22px;
left:0px;
top:0px;
margin-top:-25px;
}
.such_lnk {
font-size:16px;
color:#FF8000;
font-style:italic;
text-decoration: none;
}
.suche_lnk a:hover {
color:#FFFF00;
text-decoration: underline;
z-index:10;
}
#listing {
position:absolute;
left:5px;
top:35px;
width: 120%;
overflow:auto;
}
#searchbar{
position:absolute;
left:5px;
width:90%;
}
<div class="cont_ges">
<span class="ubers">Enter</span>
<input id="searchbar" type="text" value="Search.." onClick="this.value='';" onKeyup="search();">
<div id="listing"></div>
</div>
Work with more concentrate you have missed the clossing tags at the link and the data needed to show the link
if(pos!=-1) {
list= list + '<a class="search_lnk" href="' + terms[i]['des'] + '">'+terms[i]['des']+'</a>' + '<br>'; }
pos=-1;
}
Isn't there a JS
String.search(/regex/);
(Rhetorical Question) It takes a regular expression as its argument.
I'm having a horizontal scrolling page where arrows are indicated to scroll. I'm using the following code which works fine.
HTML:
<div id="container">
<div id="parent">
<div class="contentBlock">1</div>
<div class="contentBlock">2</div>
<div class="contentBlock">3</div>
<div class="contentBlock">4</div>
<div class="contentBlock">5</div>
</div>
<span id="panLeft" class="panner" data-scroll-modifier='-1'>Left</span>
<span id="panRight" class="panner" data-scroll-modifier='1'>Right</span>
CSS:
#container{
width:600px;
overflow-x:hidden;
}
#parent {
width:6000px;
}
.contentBlock {
font-size:10em;
text-align:center;
line-height:400px;
height:400px;
width:500px;
margin:10px;
border:1px solid black;
float:left;
}
.panner {
border:1px solid black;
display:block;
position:fixed;
width:50px;
height:50px;
top:45%;
}
.active {
color:red;
}
#panLeft {
left:0px;
}
#panRight {
right:0px;
}
Javascript:
(function () {
var scrollHandle = 0,
scrollStep = 5,
parent = $("#container");
//Start the scrolling process
$(".panner").on("mouseenter", function () {
var data = $(this).data('scrollModifier'),
direction = parseInt(data, 10);
$(this).addClass('active');
startScrolling(direction, scrollStep);
});
//Kill the scrolling
$(".panner").on("mouseleave", function () {
stopScrolling();
$(this).removeClass('active');
});
//Actual handling of the scrolling
function startScrolling(modifier, step) {
if (scrollHandle === 0) {
scrollHandle = setInterval(function () {
var newOffset = parent.scrollLeft() + (scrollStep * modifier);
parent.scrollLeft(newOffset);
}, 10);
}
}
function stopScrolling() {
clearInterval(scrollHandle);
scrollHandle = 0;
}
}());
You can also view the code in a WordPress-Installation right here: http://ustria-steila.ch/test
The arrows and the scroll works really well - but I have different sites with different amounts of text and images. So some pages need a horizontal scroll and some not. How can I add some kind of if-condition to display the arrows only if there is a horizontal overflow?
Your JavaScript code should go like this:
(function () {
var scrollHandle = 0,
scrollStep = 5,
parent = $("#container");
if(checkOverflow()){
$(".panner").show();
}
else
$(".panner").hide();
//Start the scrolling process
$(".panner").on("mouseenter", function () {
var data = $(this).data('scrollModifier'),
direction = parseInt(data, 10);
$(this).addClass('active');
startScrolling(direction, scrollStep);
});
//Kill the scrolling
$(".panner").on("mouseleave", function () {
stopScrolling();
$(this).removeClass('active');
});
//Actual handling of the scrolling
function startScrolling(modifier, step) {
if (scrollHandle === 0) {
scrollHandle = setInterval(function () {
var newOffset = parent.scrollLeft() + (scrollStep * modifier);
parent.scrollLeft(newOffset);
}, 10);
}
}
function stopScrolling() {
clearInterval(scrollHandle);
scrollHandle = 0;
}
function checkOverflow()
{
var el=document.getElementById('container');
var curOverflow = el.style.overflowX;
if ( !curOverflow || curOverflow === "visible" )
el.style.overflowX = "hidden";
var isOverflowing = el.clientWidth < el.scrollWidth;
el.style.overflowX = curOverflow;
return isOverflowing;
}
}());
I don't want to use jQuery, or any other 3rd party library!
Not working proof of concept:
<div id="Wrapper"></div>
<script>
function Build()
{
for (var i = 0 ; i < 10 ; i++)
{
var elem = document.createElement("div");
elem.setAttribute("onclick", "OnClickEvent(" + i + ")");
elem.textContent = "Hi";
document.getElementById("Wrapper").appendChild(elem);
}
}
function OnClickEvent(elementNum)
{
alert("Hi! I am " + elementNum);
}
Build();
</script>
fiddle: http://jsfiddle.net/qyzrQ/
In real life:
I'm dynamically creating a table based on ajax callback, each row contains an image button and another table. This image button should be able to hide or show corresponding inner table.
Frustrating. I was able to solve it myself.
It is enough to add (even before inserrting it into DOM):
element.setAttribute("onclick","functionName("+param+")");
Here is what i wanted to get: http://jsfiddle.net/YhY4Q/6/
And prototype (in case fiddle got deleted):
html:
<section id="Table" class="table">
<header class="row">
<div class="cell">header</div>
</header>
<script>
function ToggleShow(id) {
var elem = document.getElementById(id);
if (elem.classList.contains("invisible")) {
elem.classList.remove("invisible");
} else {
elem.classList.add("invisible");
}
}
</script>
<section id="TableWrapper">
</section>
</section>
javascript:
function ToggleShow(id) {
var elem = document.getElementById(id);
if (elem.classList.contains("invisible")) {
elem.classList.remove("invisible");
} else {
elem.classList.add("invisible");
}
}
function Build() {
var parent = document.getElementById("TableWrapper");
for (var id = 0; id < 10; id++) {
var row = document.createElement("div");
row.appendChild(HeaderRowBuilder(id));
row.appendChild(InnerTableBuilder(id));
parent.appendChild(row);
}
}
function HeaderRowBuilder(id) {
var header = document.createElement("header");
header.classList.add("row");
header.appendChild(HeaderCellBuilder(id));
var strongEle = document.createElement("strong");
strongEle.classList.add("cell");
strongEle.classList.add("cell2");
strongEle.textContent = "Something else";
header.appendChild(strongEle);
return header;
}
function HeaderCellBuilder(id) {
var div = document.createElement("div");
div.classList.add("cell");
div.appendChild(HeaderImageBuilder(id));
return div;
}
function HeaderImageBuilder(id) {
var img = document.createElement("img");
img.setAttribute("alt", "extended");
img.setAttribute("onclick", "ToggleShow('InnerTable_" + id + "')");
return img;
}
function InnerTableBuilder(id) {
var div = document.createElement("div");
div.setAttribute("id", "InnerTable_" + id);
div.textContent = "More rows, I don't care about them right now";
return div;
}
Build();
and css:
.table {
display: table;
}
.table .cell {
display: table-cell;
}
.table .cell2 {
border: 1px solid black;
width: 100%;
}
.table .spacer {
min-width: 40px;
max-width: 40px;
}
.table .cell3 {
min-width: 50px;
max-width: 50px;
}
.table .row {
display: table-row;
}
.invisible {
display: none;
}
I have made a dropdown that appears on click on a button. Pretty simple, except for how I have to click twice to get the js function to execute. After I click it the first, it appears and disappears like it should - taking only one click. I have no clue why it would require this and have searched for fixes, but none of them seem to work.
Here is my HTML:
<ul class="resources-menu">
<li>
<button onclick="res()" id="resbut" onblur="setTimeout('reshide()', 175)">Resources</button>
<ul id="resblock">
<li style="padding-bottom: 20px; text-align:center;padding-top:25px">
<button onclick="dirlnk()">Directory</button>
</li>
</ul>
</li>
</ul>
CSS:
.resources-menu {
width:88px;
float:left;
}
#resbut {
font-weight:700;
height:30px;
text-decoration:underline;
border-radius:3px;
border-color: black;
}
ul.resources-menu, ul.resources-menu ul {
list-style:none;
margin:0;
padding:0;
position: relative;
}
#resblock {
width: 90px;
background-color: lightblue;
display: none;
position: absolute;
border-bottom-left-radius: 15px;
border-bottom-right-radius:15px;
border-top-right-radius:10px;
border:solid;
border-color:black;
}
JavaScript
function res() {
if (document.getElementById('resblock').style.display == 'none') {
document.getElementById('resblock').style.display = 'block';
document.getElementById('resbut').style.background = "lightblue";
document.getElementById('resbut').style.borderBottomRightRadius = "0px";
document.getElementById('resbut').style.borderBottomLeftRadius = "0px";
document.getElementById('resbut').style.borderBottom = "none";
document.getElementById('resbut').style.textDecoration = "none";
} else {
document.getElementById('resblock').style.display = 'none';
document.getElementById('resbut').style.background = "";
document.getElementById('resbut').style.borderBottomRightRadius = "";
document.getElementById('resbut').style.borderBottomLeftRadius = "";
document.getElementById('resbut').style.borderBottom = "";
document.getElementById('resbut').style.textDecoration = "";
}
}
function reshide() {
document.getElementById('resblock').style.display = 'none';
document.getElementById('resbut').style.background = "";
document.getElementById('resbut').style.borderBottomRightRadius = "";
document.getElementById('resbut').style.borderBottomLeftRadius = "";
document.getElementById('resbut').style.borderBottom = "";
document.getElementById('resbut').style.textDecoration = "";
}
function dirlnk() {
window.location = "/Portal/directory";
}
You're looking at the style property when it's in the CSS files, not a style attribute. Use getComputedStyle instead:
function res() {
var resblock = document.getElementById('resblock');
var resblockStyle = resblock.style;
var resbutStyle = document.getElementById('resbut').style;
if (getComputedStyle(resblock).display === 'none') {
resblockStyle.display = 'block';
resblockStyle.background = "lightblue";
resbutStyle.borderBottomRightRadius = "0px";
resbutStyle.borderBottomLeftRadius = "0px";
resbutStyle.borderBottom = "none";
resbutStyle.textDecoration = "none";
} else {
reshide();
}
}
function reshide() {
var resblockStyle = document.getElementById('resblock').style;
var resbutStyle = document.getElementById('resbut').style;
resblockStyle.display = 'none';
resbutStyle.background = "";
resbutStyle.borderBottomRightRadius = "";
resbutStyle.borderBottomLeftRadius = "";
resbutStyle.borderBottom = "";
resbutStyle.textDecoration = "";
}
function dirlnk() {
window.location.href = "/Portal/directory";
}
It's also a good idea to cache your variables so you don't need to query the DOM for each style addition. Your reshide function does the same thing as the else in your res function -- you should avoid duplicating code where practicable.
Compatibility issues
As #garromark correctly notes, this solution won't work if you need to support older browsers (i.e. IE8 and below). Alternatively, you can add a class called .no-display and check whether that class is present or not:
.no-display {
display: none !important;
}
Then your JavaScript check:
if (/\bno\-display\b/.test(resblock.className)) {