Multiple drag & drop buttons and target DIVs with HTML5 - javascript

I have a couple of buttons, which stand for available webservices in form of maps or graphs. The user would be able to drag the buttons in different DIVs of various sizes on the screen, in order to compose for himself a context on the GUI which fits his needs.
I am not very familiar with the drag-and-drop functionalities of HTML5 and jQuery. I have set up an example, which works fine for a single button and single DIV. But working with multiple buttons and multiple DIVs, I wonder if that workflow of mine is the right one.
I have set up a Fiddle here. The first button can be dragged to the first DIV, and an image (just a placeholder) appears. The others don't work yet.
As the DIVs and Buttons are called by IDs, I could now just have four different IDs for the buttons and four different IDs for the DIVs. But that would that mean that I have to write four times the same javascript code, with the different IDs hard-coded into it? I guess there is a more flexible solution to this, no? Especially, as the target DIVs must stay flexible...
I wonder too how I can avoid of having the button disappear, once it is being dragged. I would rather want to make it grey or so.
Thanks for any hints!
The GUI would look like this:
For the buttons, I have this:
<div id="a-draggable-div" draggable="true" ondragend="onDragEnd(event)" ondragstart="onDragStart(event)" style="float: left">
<h4 style="float: left">Map :: Precipitation</h4>
</div>
<div style="float: left">
<h4 style="float: left">Map :: Temperature</h4>
</div>
<div style="float: left">
<h4 style="float: left">Graph :: Precipitation</h4>
</div>
<div style="">
<h4 style="float: left">Graph :: Temperature</h4>
</div>
<br clear="all" />
<div id="dropzone1" class="static" ondrop="onDrop(event)" ondragover="onDragOver(event)" ondragleave="onDragLeave(event)"></div>
<div id="dropzone2" class="static" ondrop="onDrop(event)" ondragover="onDragOver(event)" ondragleave="onDragLeave(event)"></div>
<div id="dropzone3" class="static" ondrop="onDrop(event)" ondragover="onDragOver(event)" ondragleave="onDragLeave(event)"></div>
For the javascript part:
function onDragOver(e) {
e.preventDefault();
e.target.className = "over-me";
}
function onDragLeave(e) {
e.target.className = "static";
}
function onDragStart(e) {
e.target.innerHTML = "<h4>You are Dragging me</h4>";
document.getElementById('dropzone1').className = 'drop-into-me'
}
function onDragEnd(e) {
e.target.innerHTML = "<h4>Drag Me into the Box :)</h4>";
document.getElementById('dropzone1').className = 'static'
if (e.target.parentElement.id === "dropzone1") {
e.target.innerHTML = "<img src='http://ede.grid.unep.ch/images/logo_geo.gif'>";
}
}
function onDrop(e) {
e.preventDefault();
var draggableDiv = document.getElementById("a-draggable-div");
draggableDiv.setAttribute("draggable", "false");
e.target.appendChild(draggableDiv);
}
For the CSS:
#dropzone1, #dropzone2, #dropzone3 {
width: 350px;
height: 70px;
padding: 10px;
}
.static {
border: 1px solid #aaaaaa;
}
.drop-into-me {
border: 1px dotted #aaaaaa;
}
.over-me {
background-color: yellow;
border: 1px dotted #aaaaaa;
}
h4 {
background-color: #44c767;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
border: 1px solid #18ab29;
display: inline-block;
cursor: pointer;
color: #ffffff;
font-family: Verdana;
font-size: 15px;
padding: 7px 31px;
text-decoration: none;
text-shadow: 0px 1px 6px #0e2b0a;
margin-right: 20px
}

Here is a solution for which you need not to use id You can have as many number of buttons and corresponding number of divs to drop in.
Have given ids to divs where you will be dropping the buttons just to show in which div the button have been dropped in.
Here is the updated Fiddle.
//just to know which button is being dragged we will use this variable
var draggingDiv;
function onDragOver(e) {
e.preventDefault();
e.target.classList.add("over-me");
}
function onDragLeave(e) {
e.target.classList.add("static");
e.target.classList.remove("over-me");
}
function onDragStart(e) {
draggingDiv=e.target;
e.target.innerHTML = "<h4>You are Dragging me</h4>";
}
function onDragEnd(e) {
e.target.innerHTML = "<h4>Drag Me into the Box :)</h4>";
e.target.parentElement.classList.add("static");
draggingDiv.innerHTML="<h4>Dragged once Can't drag me now:)</h4>";
// e.target.innerHTML = "<h4>You Dropped Me In "+e.target.parentElement.id+"</h4>";
}
function onDrop(e) {
e.preventDefault();
e.target.classList.remove("over-me");
//uncommment the below line if want that the button should not be draggable once it has been dropped in a div already
//draggingDiv.draggable=false;
//e.target.appendChild(draggingDiv);/commented as this will take the button to the div but we want it to at the original pposition
e.target.innerHTML="<span>Please Change My innerHTML or call some function that loads data That handles the graph/map creation in this Div</span>";
}
.dropzone {
width: 350px;
height: 70px;
padding: 10px;
}
.static {
border: 1px solid #aaaaaa;
}
.drop-into-me {
border: 1px dotted #aaaaaa;
}
.over-me {
background-color: yellow;
border: 1px dotted #aaaaaa;
}
h4 {
background-color: #44c767;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
border: 1px solid #18ab29;
display: inline-block;
cursor: pointer;
color: #ffffff;
font-family: Verdana;
font-size: 15px;
padding: 7px 31px;
text-decoration: none;
text-shadow: 0px 1px 6px #0e2b0a;
margin-right: 20px
}
<div draggable="true" ondragend="onDragEnd(event)" ondragstart="onDragStart(event)" style="float: left">
<h4 style="float: left">Map :: Precipitation</h4>
</div>
<div style="float: left" draggable="true" ondragend="onDragEnd(event)" ondragstart="onDragStart(event)">
<h4 style="float: left">Map :: Temperature</h4>
</div>
<div style="float: left" draggable="true" ondragend="onDragEnd(event)" ondragstart="onDragStart(event)">
<h4 style="float: left">Graph :: Precipitation</h4>
</div>
<div style="float: left" draggable="true" ondragend="onDragEnd(event)" ondragstart="onDragStart(event)">
<h4 style="float: left">Graph :: Temperature</h4>
</div>
<br clear="all" />
<div id="dropzone1" class="static dropzone" ondrop="onDrop(event)" ondragover="onDragOver(event)" ondragleave="onDragLeave(event)"></div>
<div id="dropzone2" class="static dropzone" ondrop="onDrop(event)" ondragover="onDragOver(event)" ondragleave="onDragLeave(event)"></div>
<div id="dropzone3" class="static dropzone" ondrop="onDrop(event)" ondragover="onDragOver(event)" ondragleave="onDragLeave(event)"></div>
<div id="dropzone4" class="static dropzone" ondrop="onDrop(event)" ondragover="onDragOver(event)" ondragleave="onDragLeave(event)"></div>
Hope it helps :)

Related

Hide and show DIV with javascript parameter

I am trying to do an event for hide and show with pure Javascript string parameters. I want to hide the other div once one of them is displayed (Let's say there are multiple div).
I tried to do it my own but I only managed to display once clicked. I had no idea how to hide the rest and only show that specified div.
Below is my code:
function show(id) {
if (document.getElementById('div_'+id).style.display == 'none') {
document.getElementById('div_'+id).style.display = 'block';
}
return false;
}
.title {
border:1px solid red;
display: inline-block;
font-size: 16px;
}
.content {
border: 1px solid blue;
display: inline-block;
font-size: 16px;
width: 300px;
}
<div class="title" onclick="show('first');">Title 1</div>
<div class="content" id="div_first" style="display:none;">Content 1
</div>
<div class="title" onclick="show('sec');">Title 2</div>
<div class="content" id="div_sec" style="display:none;">Content 2
</div>
You can use data-* attribute to store the target selector.
Don't use inline on* handlers. Keep your JS in one place.
Use CSS .is-active to manipulate the visibility state like display: block;
const showBtn = document.querySelectorAll('[data-show]');
const content = document.querySelectorAll('.content');
function show(ev) {
const selector = ev.currentTarget.getAttribute('data-show');
const elToShow = document.querySelectorAll(selector);
content.forEach(el => el.classList.remove('is-active'));
elToShow.forEach(el => el.classList.add('is-active'));
}
showBtn.forEach(el => el.addEventListener('click', show));
.title {
border:1px solid red;
display: inline-block;
font-size: 16px;
}
.content {
border: 1px solid blue;
display: inline-block;
font-size: 16px;
width: 300px;
display: none; /* ADD THIS */
}
.content.is-active{ /* ADD THIS */
display: block;
}
<div class="title" data-show="#content-1">Title 1</div>
<div class="title" data-show="#content-2">Title 2</div>
<div class="content" id="content-1">Content 1</div>
<div class="content" id="content-2">Content 2</div>
Just keep track of the id or element that is being displayed so that you can hide it if another one is selected. There's no need to iterate over them to hide them all, as you will know which one is being displayed, or to query the DOM each time to get the current one, as you can just keep a reference to it the first time.
I have updated the logic to toggle them if you click the same one twice and removed the inline event listeners, which I've moved to JS.
Note I have also replaced the <div>s for the .title elements with <button>s, as they will work better with keyboard navigation, mouse events and screen readers. You could also use <a>s instead.
let currentContentTab = null;
function show(e) {
// Using e.target you can get a reference to the clicked button:
const contentTab = document.getElementById(`div${ e.target.id.substring(3) }`);
const isHidden = contentTab.style.display === 'none';
// Toggle the panel we have just clicked (assuming you want to allow closing all of them again):
contentTab.style.display = isHidden ? 'block' : 'none';
// Hide the previous one, if any:
if (currentContentTab) {
currentContentTab.style.display = 'none';
}
// Keep track of the one we are currently displaying:
currentContentTab = isHidden ? contentTab : null;
}
// No need to have inline JS, you can bind the event listeners from JS:
for (const button of document.querySelectorAll('.title')) button.onclick = show;
body {
font-family: monospace;
font-size: 16px;
}
.title {
font-family: monospace;
font-size: 16px;
border: 1px solid red;
background: transparent;
padding: 8px;
outline: none;
}
.content {
border: 1px solid blue;
width: 300px;
padding: 8px;
margin-top: 8px;
}
<button class="title" id="tab1">Title 1</button>
<button class="title" id="tab2">Title 2</button>
<button class="title" id="tab3">Title 3</button>
<button class="title" id="tab4">Title 4</button>
<div class="content" id="div1" style="display:none; ">
Content 1...
</div>
<div class="content" id="div2" style="display:none; ">
Content 2...
</div>
<div class="content" id="div3" style="display:none; ">
Content 3...
</div>
<div class="content" id="div4" style="display:none; ">
Content 4...
</div>
If accessibility is important for you, you might want to add some ARIA attributes and the HTML hidden attribute:
let currentTab = null;
let currentPanel = null;
function show(e) {
const tab = e.target;
const id = tab.getAttribute('aria-controls');
const panel = document.getElementById(id);
// Toggle the panel we have just clicked:
tab.toggleAttribute('aria-selected');
panel.toggleAttribute('hidden');
// Hide the previous one, if any:
if (currentTab) {
currentTab.removeAttribute('aria-selected');
currentPanel.setAttribute('hidden', true);
}
// Keep track of the one we are currently displaying:
if (currentTab === tab) {
currentTab = null;
currentPanel = null;
} else {
currentTab = tab;
currentPanel = panel;
}
}
for (const button of document.querySelectorAll('.title')) button.onclick = show;
body {
font-family: monospace;
font-size: 16px;
}
.title {
font-family: monospace;
font-size: 16px;
border: 1px solid red;
background: transparent;
padding: 8px;
outline: none;
}
.content {
border: 1px solid blue;
width: 300px;
padding: 8px;
margin-top: 8px;
}
<button class="title" role="tab" aria-selected="true" aria-controls="div1" id="tab1">Title 1</button>
<button class="title" role="tab" aria-selected="true" aria-controls="div2" id="tab2">Title 2</button>
<button class="title" role="tab" aria-selected="true" aria-controls="div3" id="tab3">Title 3</button>
<button class="title" role="tab" aria-selected="true" aria-controls="div4" id="tab4">Title 4</button>
<div class="content" id="div1" role="tabpanel" aria-labelby aria-labelledby="tab1" hidden>
Content 1...
</div>
<div class="content" id="div2"role="tabpanel" aria-labelby aria-labelledby="tab2" hidden>
Content 2...
</div>
<div class="content" id="div3"role="tabpanel" aria-labelby aria-labelledby="tab3" hidden>
Content 3...
</div>
<div class="content" id="div4"role="tabpanel" aria-labelby aria-labelledby="tab4" hidden>
Content 4...
</div>
This JS code will grab all .content divs and will hide them unless it's the one we clicked.
function show(id) {
const el = document.getElementById('div' + id);
if (el.style.display == 'none') {
el.style.display = 'block';
}
const otherEls = document.querySelectorAll('.content');
otherEls.forEach(function (elItem) {
if (el !== elItem) {
elItem.style.display = 'none';
}
});
return false;
}
My solution as the following:
function show(id)
{
var divs=document.getElementsByClassName("content");
for (i=0;i<divs.length;i++)
{
divs[i].style.display='none';
}
document.getElementById('div_'+id).style.display = 'block';
}
.title {
border:1px solid red;
display: inline-block;
font-size: 16px;
}
.content {
border: 1px solid blue;
display: inline-block;
font-size: 16px;
width: 300px;
}
<div class="title" onclick="show('first');">Title 1</div>
<div class="content" id="div_first" style="display:none;">Content 1
</div>
<div class="title" onclick="show('sec');">Title 2</div>
<div class="content" id="div_sec" style="display:none;">Content 2
</div>

How to highlight and detect mouse clicks on a css grid row?

I'm trying to create a menu which I'm laying out using CSS grid. The problem that I'm having is figuring out how I can make the menu interactive when the mouse is hovering over each menu item.
I would like to be able to highlight the entire row when the mouse is over any of the menu items in the row. I can highlight each individual grid cell by adding a :hover css rule, but I don't know how to highlight the entire grid row.
The second part is then detecting when a row is being clicked. Again, I can add an onClick event handler to each cell but that doesn't seem ideal, as users could accidentally click in the gap between grid cells. I was thinking that if I can figure out how to highlight the entire row, then i could add the click handler to this row highlighter and that would solve the gap click problem.
I have created a codepen example that demonstrates how the menu is currently constructed: https://codepen.io/marekKnows_com/pen/RqMgGw
HTML:
<div class="myGrid">
<div class="anchor" id="item1">
<i class="image material-icons">folder_open</i>
</div>
<span class="text">Open...</span>
<span class="shortcut">Ctrl+O</span>
<div class="anchor" id="item2">
<i class="image material-icons">save</i>
</div>
<span class="text">Save...</span>
<span class="shortcut">Ctrl+S</span>
<div class="anchor" id="item3"></div>
<span class="text">Action</span>
<div class="separator"></div>
<div class="anchor" id="item4"></div>
<span class="text">Exit</span>
<span class="shortcut">Ctrl+X</span>
</div>
CSS:
.myGrid {
border: 1px solid black;
display: grid;
grid-template-columns: 20px auto auto;
grid-gap: 2px 6px;
align-items: center;
justify-items: start;
padding: 10px;
box-sizing: border-box;
}
.image {
width: 24px;
}
.text {
height: 28px;
line-height: 28px
}
.shortcut {
justify-self: end;
padding: 0 5px;
height: 28px;
line-height: 28px
}
.separator {
grid-column: 1 / span 3;
width: 100%;
height: 3px;
border-bottom: 1px solid lightgray;
}
One option is to wrap the row elements with a div, include style display: contents; in the wrapper div, add the click handler to the wrapper div.
CSS grid will treat the elements inside the wrapper as if there was no wrapper when laying out the contents, so they will be aligned as you desire. See MDN display-box for more info. That link also points out browsers have accessibility bugs with display: contents;.
I have tested only with Firefox so far.
<div class="myGrid">
<div class="row" onclick="console.log('click');">
<div class="anchor" id="item1">
<i class="image material-icons">folder_open</i>
</div>
<span class="text">Open...</span>
<span class="shortcut">Ctrl+O</span>
</div>
<div class="row" onclick="console.log('click');">
<div class="anchor" id="item2">
<i class="image material-icons">save</i>
</div>
<span class="text">Save...</span>
<span class="shortcut">Ctrl+S</span>
</div>
<div class="row" onclick="console.log('click');">
<div class="anchor" id="item3"></div>
<span class="text">Action</span>
</div>
<div class="separator"></div>
<div class="row" onclick="console.log('click');">
<div class="anchor" id="item4"></div>
<span class="text">Exit</span>
<span class="shortcut">Ctrl+X</span>
</div>
</div>
.myGrid {
border: 1px solid black;
display: grid;
grid-template-columns: 20px auto auto;
grid-gap: 2px 6px;
align-items: center;
justify-items: start;
padding: 10px;
box-sizing: border-box;
}
.row {
display: contents;
}
.image {
width: 24px;
}
.text {
height: 28px;
line-height: 28px
}
.shortcut {
justify-self: end;
padding: 0 5px;
height: 28px;
line-height: 28px
}
.separator {
grid-column: 1 / span 3;
width: 100%;
height: 3px;
border-bottom: 1px solid lightgray;
}
I finally got it to work. What I ended up doing was making the anchor element have position relative. Then I added a new div with position absolute under the anchor element. From within JavaScript I can size the new element to be the full width of the grid and using z-index I can position it relative to the other elements in the row accordingly.
Firstly, you might want to change your html so the .anchor elements are wrapping each item.
<div class="myGrid">
<div class="anchor" id="item1">
<i class="image material-icons">folder_open</i>
<span class="text">Open...</span>
<span class="shortcut">Ctrl+O</span>
</div>
<div class="anchor" id="item2">
<i class="image material-icons">save</i>
<span class="text">Save...</span>
<span class="shortcut">Ctrl+S</span>
</div>
<div class="anchor" id="item3">
<span class="text">Action</span>
</div>
<div class="separator"></div>
<div class="anchor" id="item4">
<span class="text">Exit</span>
<span class="shortcut">Ctrl+X</span>
</div>
</div>
And then use flex to align the contents of each item
.myGrid {
border: 1px solid black;
padding: 10px;
box-sizing: border-box;
}
.anchor {
display: flex;
justify-content: flex-start;
}
/* Hover for each anchor */
.anchor:hover {
background: red;
}
.image {
width: 24px;
}
.text {
height: 28px;
line-height: 28px
}
.shortcut {
margin-left: auto; /* push the shortcut to the right */
padding: 0 5px;
height: 28px;
line-height: 28px
}
.separator {
grid-column: 1 / span 3;
width: 100%;
height: 3px;
border-bottom: 1px solid lightgray;
}
https://codepen.io/anon/pen/xQWLaE
.anchor:hover >
.mygrid
{ background:red }
check this if it works on hovering item1 it will change the border color(from black to red as highlighting)

jQuery slider/switcher/tabs

I had no idea how to title this topic, sorry for that. I am building simple shopping cart splited into few steps. The whole thing is supposed to work similar to sliders or well-known tabs.
Let's see the code to make things easier.
$(document).ready(function(){
$('.stepNumber').click(function(e) {
e.preventDefault();
var stepDesc = $(this).next('.stepDesc');
if(!stepDesc.is(':visible')) {
$('.step').removeClass('stepActive');
$(this).parent().addClass('stepActive');
}
var val = parseInt($('.step.stepActive').children('div.stepNumber').text());
switch(val) {
case 1:
$('.formStepTwo').hide();
$('.formStepOne').show();
break;
case 2:
$('.formStepOne').hide();
$('.formStepTwo').show();
break;
case 3:
alert('blabla');
break;
}
});
});
.formStep {
display: none;
}
step {
float: left;
border: 1px solid #333;
margin-right: 5px;
}
.stepNumber {
background: #333;
color: #fff;
float: left;
padding: 6px 10px;
}
.stepDesc {
text-align: left;
padding: 6px 10px;
width: 150px;
display: none;
}
.stepActive > .stepDesc {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="step stepOne stepActive">
<div class="stepNumber">1</div>
<div class="stepDesc">Cart</div>
</div>
<div class="step stepTwo">
<div class="stepNumber">2</div>
<div class="stepDesc">Client data</div>
</div>
<div class="step stepThree">
<div class="stepNumber">3</div>
<div class="stepDesc">Shipping data</div>
</div>
<div class="formStep formStepOne">
Something - tab content
</div>
<div class="formStep formStepTwo">
Something else
</div>
Sorry for the appearance, some cosmetic css is missing here.
The actual problem:
I want to add button "Next" just under my "tab content". If we're in the step 1 at this moment, clicking that button should take us to step 2 and so on.
In the meantime time our "tab menu" script should be activated - as in the snippet: close description of others step, show current description and add class "stepActive".
Almost the same thing you can find in common sliders: arrows (next, prev) to move between slides and also "dot menu" with correct dot being highlighted.
If I'm not mistaken, it's something like that, what you wanted, isn't it?
$(document).ready(function(){
$('.stepNumber:contains(3)').click(function(){
alert('blabla');
});
$('.nextStep').click(function (e) {
e.preventDefault();
var stepActive = $('.stepActive');
if (stepActive.next('.step').length)
stepActive.next().children('.stepNumber')[0].click();
else
$('.step > .stepNumber')[0].click();
});
$('.stepNumber').click(function(e) {
e.preventDefault();
var obj = $(this);
var parent = obj.parent();
var stepDesc = obj.next('.stepDesc');
if(!stepDesc.is(':visible')) {
$('.step').removeClass('stepActive');
parent.addClass('stepActive');
}
$('[id^=step]').hide();
$('#step' + obj.text()).show();
});
$('.stepNumber')[0].click();
});
.formStep {
display: none;
}
.step {
float: left;
border: 1px solid #333;
margin-right: 5px;
}
.stepNumber, .nextStep {
background: #333;
color: #fff;
float: left;
padding: 6px 10px;
}
.stepDesc {
text-align: left;
padding: 6px 10px;
width: 150px;
display: none;
}
.stepActive > .stepDesc {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="step">
<div class="stepNumber">1</div>
<div class="stepDesc">Cart</div>
</div>
<div class="step">
<div class="stepNumber">2</div>
<div class="stepDesc">Client data</div>
</div>
<div class="step">
<div class="stepNumber">3</div>
<div class="stepDesc">Shipping data</div>
</div>
<div id="step1" class="formStep">
Something - tab content
</div>
<div id="step2" class="formStep">
Something else
</div>
<div id="step3" class="formStep">
The last one
</div>
<div class="nextStep">Next</div>

Change attribute of multiple elements on hover by using CSS

I have two div elements which are placed next to each other, i want to change the attribute background-color of both of them if the user hovers over one of them.
So the background-color should be initially set to #d8d8d8 for both divs and should change to #cacaca on both divs if i hover over one of the divs.
I solved it using jquery:
$("#FOO").hover
(
function()
{
$(this).css("background-color","#CACACA");
$("#BAR").css("background-color","#CACACA");
},
function()
{
$(this).css("background-color","#D8D8D8");
$("#BAR").css("background-color","#D8D8D8");
}
)
$("#BAR").hover
(
function()
{
$(this).css("background-color","#CACACA");
$("#FOO").css("background-color","#CACACA");
},
function()
{
$(this).css("background-color","#D8D8D8");
$("#FOO").css("background-color","#D8D8D8");
}
)
.buttons {
border:1px solid black;
background-color: #D8D8D8;
height: 100px;
font-family: play;
font-size: 30px;
text-align:center;
vertical-align: middle;
line-height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<div class="col-xs-10 buttons" id="FOO" style="border-right: 0px">
<span style="padding-left:100px">FOO</span>
</div>
<div class="col-xs-2 buttons" id="BAR" style="border-left: 0px">
<span>BAR</span>
</div>
Is there a better way to achieve this? Maybe only with css?
You can wrap columns in div and add :hover on it:
.buttons {
border:1px solid black;
background-color: #D8D8D8;
height: 100px;
font-family: play;
font-size: 30px;
text-align:center;
vertical-align: middle;
line-height: 100px;
}
.row:hover > .buttons {
background-color: #CACACA;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<div class='row'>
<div class="col-xs-10 buttons" id="FOO" style="border-right: 0px">
<span style="padding-left:100px">FOO</span>
</div>
<div class="col-xs-2 buttons" id="BAR" style="border-left: 0px">
<span>BAR</span>
</div>
</div>
I would give both divs the same css-class like so:
<div class="col-xs-10 buttons buttonset1" id="FOO" style="border-right: 0px">
<span style="padding-left:100px">FOO</span>
</div>
<div class="col-xs-2 buttons buttonset1" id="BAR" style="border-left: 0px">
<span>BAR</span>
</div>
Then in jquery you can make the following rule:
$(".buttonset1").hover
(
function()
{
$(".buttonset1").css("background-color","#CACACA");
},
function()
{
$(".buttonset1").css("background-color","#D8D8D8");
}
)
You are more flexible this way.

Swapping an image when a toggle has been clicked on

I have the following code where I added a plus symbol to one of my service titles. I was informed by someone that when that service is clicked on I should have a minus sign take its place to show that it can be minimized. I am unsure of how to swap out the plus sign when the description has been expanded. Does anyone have any ideas of how I could do that?
Here is a snippet. Click on one of the service names to see the description expand.
$('.service_wrapper').click(function() {
var thisDescription = $('.service_description', $(this));
// Hide all other descriptions
$('.service_description').not(thisDescription).hide();
// Toggle (show or hide) this description
thisDescription.slideToggle(500);
});
.service_wrapper {
border: 1px solid black;
margin: 15px;
width: 20%;
}
.service_list {
margin-left: 20%;
}
.service_title {
padding: 15px 12px;
margin: 0;
font-weight: bold;
font-size: 1em;
}
.service_title:hover {
background-color: gray;
color: blue;
cursor: pointer;
}
.service_description {
display: none;
padding: 8px 14px;
width: 100%;
margin-top: 10px;
font-size: .9em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="service_list">
<div class="service_wrapper">
<div class="service_title">
<img src="http://realtorcatch.com/icons/plusSymbol.png" alt="Service" style="width:10px;height:10px;">Floors</div>
<div class="service_description">The best floors!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Roofs</div>
<div class="service_description">Your roof will be perfect!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Siding</div>
<div class="service_description">mmmm siding.</div>
</div>
<div class="service_wrapper">
<div class="service_title">Paint</div>
<div class="service_description">Fabulous paint!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Kitchen Remodels</div>
<div class="service_description">Pretty kitchen.</div>
</div>
</div>
Here is the working example, i change a little de html and Js
$('.service_wrapper').click(function() {
var thisDescription = $('.service_description', $(this));
var t = $(this);
if(t.hasClass('open'))
{
t.removeClass('open');
t.find('.status').html("+");
}else {
t.addClass('open');
t.find('.status').html("-");
}
// Hide all other descriptions
$('.service_description').not(thisDescription).hide();
// Toggle (show or hide) this description
thisDescription.slideToggle(500);
});
the working example
I'd suggest simply toggling a class to achieve this.
You can add the icon as a background image of a pseudo element inserted into the .service_title element. Then you can simply toggle a class in order to change the icon. Update the background image URLs accordingly. See the updated example for the modified jQuery; it's still only 5 lines.
The relevant CSS:
.service_title:before {
content: '';
background: url('http://i.stack.imgur.com/GC7i2.png') 0 0 / 10px 10px no-repeat;
width: 10px;
height: 10px;
display: inline-block;
vertical-align: middle;
}
.closed .service_title:before {
background-image: url('http://i.stack.imgur.com/ma4L4.png');
}
Updated Example:
$('.service_wrapper').click(function() {
var thisDescription = $('.service_description', $(this));
$('.service_description').not(thisDescription).hide().parent().removeClass('closed');
thisDescription.slideToggle(500).parent().toggleClass('closed');
});
.service_wrapper {
border: 1px solid black;
margin: 15px;
width: 20%;
}
.service_list {
margin-left: 20%;
}
.service_title {
padding: 15px 12px;
margin: 0;
font-weight: bold;
font-size: 1em;
}
.service_title:before {
content: '';
background: url('http://i.stack.imgur.com/GC7i2.png') 0 0 / 10px 10px no-repeat;
width: 10px;
height: 10px;
display: inline-block;
vertical-align: middle;
}
.closed .service_title:before {
background-image: url('http://i.stack.imgur.com/ma4L4.png');
}
.service_title:hover {
background-color: gray;
color: blue;
cursor: pointer;
}
.service_description {
display: none;
padding: 8px 14px;
width: 100%;
margin-top: 10px;
font-size: .9em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="service_list">
<div class="service_wrapper">
<div class="service_title">Floors</div>
<div class="service_description">The best floors!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Roofs</div>
<div class="service_description">Your roof will be perfect!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Siding</div>
<div class="service_description">mmmm siding.</div>
</div>
<div class="service_wrapper">
<div class="service_title">Paint</div>
<div class="service_description">Fabulous paint!</div>
</div>
<div class="service_wrapper">
<div class="service_title">Kitchen Remodels</div>
<div class="service_description">Pretty kitchen.</div>
</div>
</div>
You could just change it within your click binding...
Let's say your using images, just add a data-attribute you can query when you need to, like this...
HTML
<div class="service_wrapper">
<img data-state="plus" class="state" src="plus.png" alt="More"/>
<div class="service_title">Paint</div>
<div class="service_description">Fabulous paint!</div>
</div>
JS
$('.service_wrapper').click(function() {
var state = $(this).find('.state');
if(state.data('state') == 'plus')
state.attr({ 'src': 'minus.png', 'alt': 'Less' }).data('state', 'minus');
else
state.attr({ 'src': 'plus.png', 'alt': 'More' }).data('state', 'plus');
});

Categories