Keeping buttons in place when using .hide() - javascript

Not sure if this is because I'm new to meteor or if I am making an error in my syntax with my HTML or jQuery. Ideally I would like the whole grid to stay in place when a button is clicked. For example if you clicked the button in the middle of the grid there would be a empty spot where that button was before. My question is, why is it that when I click a button the button disappears but moves the whole grid and what do I do to fix this?
HTML:
<head>
<title>bubblepopper</title>
</head>
<body>
<center>{{> grid}}</center>
</body>
<template name ="grid">
<div id="container">
{{#each buttons}}
<button class="button" type="button"></button>
{{/each}}
</div>
</template>
JS:
Buttons = new Meteor.Collection("buttons");
if (Meteor.isClient) {
player = prompt("What is your name?")
Template.grid.buttons = function () {
}
Template.grid.buttons = function () {
var list = [];
for(var i=1; i<=64; i++){
list.push({value: i});
}
return list;
};
Template.grid.events({
'click .button': function(ev) {
$(ev.target).hide()
}
});
}
if (Meteor.isServer) {
}

.hide() works by adding the style display: none to the element. This removes the space used by the element in the rendered page.
If you want to make something invisible but keep its space on the page, use the visibility style:
$(ev.target).css('visibility', 'hidden');
To restore it, set the visibility to visible.

Related

JS appendChild() to a <div> in <form>

I am able to avoid the below issue by making my div a direct child of body and appending a select to the div, but am not able to achieve the same results when the div is a child of a form within body (either when appending to the div or to the form).
I am just making a drop-down table (select element) that is added to the web page when the user clicks a button. The drop-down select shows when the div is the direct child of body, but not when it is a child of a form that is a child of body. When the button is clicked using the below method, the dropdown appears for like 0.25s and then the page returns to the original layout. The same occurs when trying to append directly to the form.
<!DOCTYPE html> <!--text_index.html-->
<html>
<head>
<meta charset="UTF-8">
<title>Add Drop Down Menu to HTML w/ JS on Button Click</title>
<link rel="stylesheet" type="text/css" href="test_styles.css">
</head>
<body>
<form id="form-button">
<div id="user-area">
<button id="dropdown-button">Add a dropdown menu!</button><br /><br />
</div>
</form>
<script src="test_script.js"></script>
</body>
</html>
Now the JS is shown below. The console returns no error but the select element does not remain in the browser window.
let materialArray = ['Select Your Material:',
                    'Kryptonite',
                    'Odium',
                    'Quartz'];
let formButton = document.getElementById('form-button');
let divUserArea = document.getElementById('user-area');
let dropdownBtn = document.getElementById('dropdown-button');
/***********************************************************************/
/****BEGIN LOOP W/ BUTTON CLICK AND NAMED FUNCTION****/
//NOTE: YOU CANNOT appendChild() ON A <DIV> INSIDE A <FORM>.
////IF YOU CAN THEN THERE IS SOME LOGIC THAT I AM MISSING.
////YOU CANNOT appendChild() DIRECTLY ON A FORM EITHER.
let newSelect = document.createElement("select");
let newOption = [];
function onClickDropdownBtn () {
    for (let i = 0; i < materialArray.length; i++) {
        newOption[i] = document.createElement("option"); //create the new option for the new HTML select element
        newOption[i].text = materialArray[i]; //add the appropriate text to the new option
        newSelect.add(newOption[i], i); //add the completed option to the HTML select element
    }
divUserArea.appendChild(newSelect); //also tried formButton.appendChild(newSelect); and got same
result
return true;
}
dropdownBtn.addEventListener('click', onClickDropdownBtn);
if (onClickDropdownBtn === false) {
newSelect.style.display = 'hidden';
dropdownBtn.style.display = 'block';
} else {
newSelect.style.display = 'block';
dropdownBtn.style.display = 'hidden';
}
/****END LOOP W/ BUTTON CLICK AND NAMED FUNCTION ****/
Is there a way to append to the div inside the form, or to the form directly?
Thanks!
For gits and shiggles, here is the CSS. Maybe the issue is here?
select {
width: 200px;
height: 25px;
text-align: center;
}
button {
width: 200px;
height: 25px;
text-align: center;
}
When you put a <button> inside a form, the default type is submit, which makes the page "refresh" (that's why you only see your dropdown for a second).
You can either change your button type, like this:
<button type='button' id="dropdown-button">Add a dropdown menu!</button>
Or you can add the event.PreventDefault() in your click function to avoid the form submission, like this:
function onClickDropdownBtn (event) {
for (let i = 0; i < materialArray.length; i++) {
newOption[i] = document.createElement("option"); //create the new option for the new HTML select element
newOption[i].text = materialArray[i]; //add the appropriate text to the new option
newSelect.add(newOption[i], i); //add the completed option to the HTML select element
}
divUserArea.appendChild(newSelect); //also tried formButton.appendChild(newSelect); and got same
event.preventDefault();
return true;
}
That will keep your dropdown component in the page and you can go from there.
Forms have the default behaviour of reloading the page (they evolved in an era before SPAs). Your code works just fine, except that it also reloads the page and you lose the state (in your case, the select element).
Just change onClickDropdownBtn() to
function onClickDropdownBtn (event) {
event.preventDefault()
...
and it should be ready to go!

Toggle hide/show not working on childs div

I have a script that gets data from a Google Sheet and displays it as a webpage - using JS and Tabletop.js.
There are multiple entries in the Sheet thus multiple entries in the webpage. To organise the Data I have a hide/show button. When the button is clicked on the first entry it works. However when the any of the other buttons are clicked it hides or shows the first entries data, not its own!
How do I hide/show each individual entries data? Below is the code I am working with!
I am new to JavaScript - Thanks in advance!
P.S - I struggled writing the Title to the questions!
<link href="../common/cats-copy.css" media="screen" rel="stylesheet" type="text/css" />
</head>
<style>
#add-info {
display: none
}
</style>
<body>
<div class="container">
<h1>Resturants</h1>
<div id="content"></div>
<script id="cat-template" type="text/x-handlebars-template">
<div class="entry">
<h5>{{establishment_name}}</h5>
<h6>Area: {{area}}</h6>
<h6>Cuisine: {{cuisine}}</h6>
<button id="btn" class="button-primary" onclick="myFunction()">Hide</button>
<div id="add-info">
<h6>Address: {{address}}</h6>
<h6>Google Maps: {{google_maps_location}}</h6>
<h6>Opening Times: {{opening_times}}</h6>
<h6>Rating: {{rating}}</h6>
<h6>Added By: {{added_by}}</h6>
<h6>Date Added: {{date_added}}</h6>
</div>
</div>
</script>
</div>
<!-- Don't need jQuery for Tabletop, but using it for this example -->
<script type="text/javascript" src="handlebars.js"></script>
<script type="text/javascript" src="../../src/tabletop.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript">
var public_spreadsheet_url = 'https://docs.google.com/spreadsheets/d/1h5zYzEcBIA5zUDc9j4BTs8AcJj-21-ykzq6238CnkWc/edit?usp=sharing';
$(document).ready( function() {
Tabletop.init( { key: public_spreadsheet_url,
callback: showInfo,
parseNumbers: true } );
});
function showInfo(data, tabletop) {
var source = $("#cat-template").html();
var template = Handlebars.compile(source);
$.each( tabletop.sheets("food").all(), function(i, food) {
var html = template(food);
$("#content").append(html);
});
}
</script>
<script>
function myFunction() {
var x = document.getElementById("add-info");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
</script>
</body>
</html>
Are all the entries on your page filled from the given template, meaning they are divs with the class entry? If so, I think your issue is the following: Your entry div has a child div with the id="add-info". And when you click the button, your handler function (myFunction()) tries to get a reference to that div via document.getElementById("add-info"); Now, if you have multiple such entries on a page, you will have multiple divs with id="add-info". But the id attribute of an element must be unique in your whole document. See the description of id or that of getElementById().
So the root cause of your problem is that the same id is used multiple times in the document when it shouldn't be. You get the behavior you're seeing because getElementById() just happens to be returning a reference to the first element it finds on the page, regardless of which button you click. But I believe you're in undefined behavior territory at that point.
One way to solve the problem is to somehow give myFunction() information about which button was clicked, while making each div you'd like to manipulate unique so they can be found easier. For instance, you can use the order of the restaurant on your page as its "index", and use that as the id of the div you'd like to hide/show. And you can also pass this index as an argument when you call your click handler:
...
<button id="btn" class="button-primary" onclick="myFunction('{{index}}')">Hide</button>
<div id="{{index}}">
<!-- The rest of the code here... -->
...
... add the index into your template context, so Handlebars can fill in the {{index}} placeholder:
...
$.each( tabletop.sheets("food").all(), function(i, food) {
food.index = i // Give your context its 'index'
var html = template(food);
$("#content").append(html);
});
...
... and then alter your function slightly to use the given argument instead of always looking for the div with id="add-info":
function myFunction(indexToToggle) {
var x = document.getElementById(indexToToggle);
// rest of the code is same
With this approach, I expect your DOM to end up with divs that have ids that are just numbers ("3", "4", etc.) and your click handler should get called with those as arguments as well.
Also note that your <button> element has id="btn". If you repeat that template on your page, you will have multiple <button>s with the same id. If you start trying to get references to your buttons via id you will have similar issues with them too since the ids won't be unique.

Toggling Background Color on Click with Javascript

I am working on a class project and need to be able to toggle the background color of a transparent png on click. I have been working through a number of examples from the site, but I can't get it working. I am a total novice at Javascript and haven't had luck trying to plug in jQuery code either.
Here is the targeted section:
<div class="expenseIcon"><a href="#">
<img src="images/mortgage.png"></a><br/>
<p>Rent or Mortgage</p>
</div>
On clicking the linked image, the goal is for the background on the image to change to green. Clicking it again would change it back to the default, white. Here's the CSS I'd like to toggle on/off with click.
.colorToggle {
background: #A6D785;
}
I had tried adding class="iconLink" to the href and class="iconBox" to the image with the following Javascript adapted from another post, but it didn't work.
var obj = {};
$(document).ready(function () {
$(".iconLink").click(function () {
var text = $(this).find(".iconBox");
obj.var1 = text;
//alert(obj.var1);
//return false;
$('.iconBox').removeClass('colorToggle');
$(this).addClass('colorToggle')
});
});
Any advice would be greatly appreciated!
Let's break down what is happening with your current code when you click the link.
var obj = {};
$(document).ready(function () {
$(".iconLink").click(function () {
var text = $(this).find(".iconBox");
obj.var1 = text;
$('.iconBox').removeClass('colorToggle');
$(this).addClass('colorToggle')
});
});
JQuery finds all elements with the classname "iconBox". In your case, this is the img element. The reference to that element is then saved in "obj.var1". You do not end up doing anything with this reference, so these two lines can be removed.
All elements with the class "iconBox" have the class "colorToggle" removed. Your img element didn't have this class on it, so nothing happens.
The class "colorToggle" is added to the anchor element. Yes! Now the element wrapping the img has a background color.
Unfortunately, clicking the anchor tag again won't do anything, since the anchor tag will already have the "colorToggle" class and all we would be doing would be trying to add it again. Hmm. Let's try changing addClass to toggleClass. Here's our new code:
$(document).ready(function () {
$(".iconLink").click(function () {
$(this).toggleClass('colorToggle');
}
});
Also, note that because we're working with the anchor element, the p element won't be affected by this change. If you want the entire div to change background colors, use this line instead:
$(".expenseIcon").toggleClass('colorToggle');
Using the given markup:
<!-- to toggle the bg-color onClick of anchor tag -->
<div class="expenseIcon">
<a href="#">
<img src="images/mortgage.png">
</a>
<br/>
<p>Rent or Mortgage</p>
</div>
since the question asks for javascript, heres an option for updating the background-color of an element using the built-in js.style method
//get a handle on the link
//only one element w/ className 'expenseIcon'
//first child of 'expenseIcon' is the anchor tag
var link = document.getElementsByClassName('expenseIcon')[0].children[0];
//get a handle on the image
var image = link.children[0];
//listen for click on link & call bgUpdate()
link.addEventListener('click', bgUpdate, false);
function bgUpdate() {
if(image.style.backgroundColor === 'lightgoldenrodyellow'){
image.style.backgroundColor = 'aliceblue';
} else if (image.style.backgroundColor === 'aliceblue') {
image.style.backgroundColor = 'lightgoldenrodyellow';
}
else console.log('image bgColor: ' + image.style.backgroundColor);
}
a similar example
css
.expenseIcon{
background: red;
}
.colorToggle {
background: blue;
}
jquery
$(".expenseIcon").click(function () {
$('.expenseIcon').toggleClass('colorToggle');
});
By default, the div will have expenseIcon background. ToggleClass will toggle the div class with colorToggle so will override the previous color.
You don't need an hyperlink tag A to manage clicks, just put it on the DIV.

Simple Way to Switch a CSS Class in Javascript

I appreciate all the suggestions I've gotten so far-thank you!
I'll try to describe a bit better what I'm trying to do:
I want to switch a CSS class on the active (clicked on) tab item on a item (to make a highlight effect while its related content is showing).
The JS Fiddle http://jsfiddle.net/4YX5R/9/ from Vlad Nicula comes close to what I'm trying to achieve, however I can't get it to work in my code.
The tabs are linked to content which is shown on the page when the tab is clicked. This part is working fine. I just want to change the CSS style on the ContentLink items when its content is being shown.
I'd also like to keep the content for ContentLink1 visible when the page loads, as it is now in the code, and for ContentLink1 to have the CSS .infoTabActive class when the page loads. When the ContentLink tab is not clicked, it should have the .infoTab class.
This is what I have so far:
HTML:
<article class="grid-70 infoContainer">
<a class="infoTab" id="aTab" href="javascript:show('a')">ContentLink1</a>
<a class="infoTab" id="bTab" href="javascript:show('b')">ContentLink2</a>
<a class="infoTab" id="cTab" href="javascript:show('c')">ContentLink3</a>
<div id="a">
<p> Inhalt 1111111.</p></div>
<div id="b">
<p>Inhalt 222222222
</p></div>
<div id="c">
<p>Inhalt 33333333
<7p></div>
</article>
Javascript:
window.onload = function () {
document.getElementById("a").style.display = "block";
}
function show(i) {
document.getElementById('a').style.display ="none";
document.getElementById('b').style.display ="none";
document.getElementById('c').style.display ="none";
document.getElementById(i).style.display ="block";
}
basic CSS for tab styles I want to apply:
.infoTab {
text-decoration:none;
color:red;
}
.infoTabActive {
text-decoration:none;
color:yellow;
}
Any pointers would be appreciated!
You can switch the classes simply bu using class property on DOM element.
To replace the existing class use
document.getElementById("Element").className = "ClassName";
Similarly to add a new class to exisiting classes use
document.getElementById("Element").className += "ClassName";
Change show function to be like this:
function show(i) {
document.getElementById('a').style.display ="none";
document.getElementById('a').className ="";
document.getElementById('b').style.display ="none";
document.getElementById('b').className ="";
document.getElementById('c').style.display ="none";
document.getElementById('c').className ="";
document.getElementById(i).style.display ="block";
document.getElementById(i).className ="selected";
}
I changed a little bit your code to make it suits your needs.
First, change the onload part in the Fiddle, by no wrap.
Then, you need to hide each elements at start like this :
window.onload = function () {
var list = document.getElementsByClassName("hide");
for (var i = 0; i < list.length; i++) {
list[i].style.display = "none";
}
}
I added an hide class to achieve it. Your show function works well then.
I would do it like this:
add a class called .show which sets the element to display block.
then toggle the classname.
Here's a JSFiddle
And here's an example:
HTML
<article class="grid-70 infoContainer">
<a class="infoTab" id="aTab" href="javascript:show('a')">Werbetexte</a>
<a class="infoTab" id="bTab" href="javascript:show('b')">Lektorate</a>
<a class="infoTab" id="cTab" href="javascript:show('c')">Übersetzung</a>
<div class="box" id="a">
<div class="col1"> <p>Inhalt 1111111.</p></div>
</div>
<div class="box" id="b">
Inhalt 222222222
</div>
<div class="box" id="c">
Inhalt 33333333
</div>
</article>
JavaScript
window.onload = function () {
show('a');
}
function show(elm) {
// get a list of all the boxes with class name box
var shown = document.getElementsByClassName('box');
// loop through the boxes
for( var i=0; i<shown.length; i++ )
{
// set the classname to box (removing the 'show')
shown[i].className = 'box';
}
// change the classname to box show for the element that was clicked
document.getElementById( elm ).className = 'box show';
}
CSS
.box {
display:none;
}
.box.show {
display:block;
}
Simplest way I could think of is this : http://jsfiddle.net/4YX5R/9/
Basically you don't want to listen to each element. If you do that you will have issues with new tabs. If you listen to the parent element like in my example you can add new tabs without having to write any more javascript code.
<a class="infoTab" data-target='a' id="aTab">Werbetexte</a>
Each tab button has a data-target attribute that will describe the div to show as the tab content. Hiding and showing content will be done via css, not style - which is a recommended best practice -.
tabs.addEventListener("click", function ( ev ) {
var childTarget = ev.originalTarget || ev.toElement;
...
}
When a tab is clicked, we check to see which element was clicked from the event listener on the parent, and then get the data-target from it. We use this as a id selector to show the new tab. We also need a reference to the old tab that was active, so we can hide it.
The logic is not that complicated, and with this you can have any number of tabs. I would recommend jQuery for this, since the event delegation might not work in all browsers with the current code.
I hope this helps :)

CSS/Javascript Mouseover Popup box

I have table cell with a javascript/css content box that pops up upon mouseover.
There are 20 cells on the page. Everything is working correctly, in that when you mouseover the product link, you see the content box. However, I want to put a LINK inside the content box that the user can click on if they choose. So, the popup box has to stay up long enough for the user to mouseover to click the link.
Really, I want the OnMouseOver to stay open until either a second or two has gone by and/or the user OnMouseOver's another cell.
The problem I'm having is that the pop up box doesn't stay open (due to OnMouseOut) to click the link. If I turn OnMouseOut off (which I tried), then all the pop up boxes just stay open, so this doesn't do the job either.
My CSS looks like this:
<style type="text/css" title="">
.NameHighlights {position:relative; }
.NameHighlights div {display: none;}
.NameHighlightsHover {position:relative;}
.NameHighlightsHover div {display:block;position:absolute;width: 15em;top:1.3em;*top:20px;left:70px;z-index:1000;}
</style>
And the html:
<td>
<span class="NameHighlights" onMouseOver="javascript:this.className='NameHighlightsHover'" onMouseOut="javascript:this.className='NameHighlights'">
Product 1
<div>
# of Votes: 123<br>
% Liked<br>
<a href="product review link>See User reviews</a>
</div>
</span>
</td>
So, how can I make the pop up box stay open long enough to click on the link, but also make it disappear if another content box is activated?
Thanks in advance.
You have to improve your HTML markup for this task, need to get rid of inline event handlers:
<span class="NameHighlights">
Product 1
<div>
# of Votes: 123<br>
% Liked<br>
See User reviews
</div>
</span>
Then you have to bind your events to all .NameHighlights spans:
var span = document.querySelectorAll('.NameHighlights');
for (var i = span.length; i--;) {
(function () {
var t;
span[i].onmouseover = function () {
hideAll();
clearTimeout(t);
this.className = 'NameHighlightsHover';
};
span[i].onmouseout = function () {
var self = this;
t = setTimeout(function () {
self.className = 'NameHighlights';
}, 300);
};
})();
}
http://jsfiddle.net/3wyHJ/
So the idea is to use setTimeout method.
Notes: I used querySelectorAll which is not supported by IE7, if you need to support it then you can use any of implementations of the getElementsByClassName method.
In case anyone is looking for a jQuery version of the accepted answer:
var t;
$(function(){
$('span.NameHighlights').mouseover(
function(e){
hideAll();
clearTimeout(t);
$(this).attr('class', 'NameHighlightsHover');
}
).mouseout(
function(e){
t = setTimeout(function() {
//$(this).attr('class', 'NameHighlights');
hideAll();
}, 300);
}
);
});
function hideAll() {
$('span.NameHighlightsHover').each(function(index) {
console.log('insde hideAll');
$(this).attr('class', 'NameHighlights');
})
};
jsFiddle

Categories

Resources