Twitter bootstrap collapse: change display of toggle button - javascript

I am using Twitter Bootstrap to create collapsible sections of text. The sections are expanded when a + button is pressed. My html code as follows:
<div class="row-fluid summary">
<div class="span11">
<h2>MyHeading</h2>
</div>
<div class="span1">
<button type="button" class="btn btn-success" data-toggle="collapse" data-target="#intro">+</button>
</div>
</div>
<div class="row-fluid summary">
<div id="intro" class="collapse">
Here comes the text...
</div>
</div>
Is there a way to change the button to display - instead of + after the section is expanded (and change back to + when it is collapsed again)?
Additional information: I hoped there would be a simple twitter-bootstrap/css/html-based solution to my problem. All responses so far make use of JavaScript or PHP. Because of this I want to add some more information about my development environment: I want to use this solution inside a SilverStripe-based (version 3.0.5) website which has some implications for the use of both PHP as well as JavaScript.

try this. http://jsfiddle.net/fVpkm/
Html:-
<div class="row-fluid summary">
<div class="span11">
<h2>MyHeading</h2>
</div>
<div class="span1">
<button class="btn btn-success" data-toggle="collapse" data-target="#intro">+</button>
</div>
</div>
<div class="row-fluid summary">
<div id="intro" class="collapse">
Here comes the text...
</div>
</div>
JS:-
$('button').click(function(){ //you can give id or class name here for $('button')
$(this).text(function(i,old){
return old=='+' ? '-' : '+';
});
});
Update With pure Css, pseudo elements
http://jsfiddle.net/r4Bdz/
Supported Browsers
button.btn.collapsed:before
{
content:'+' ;
display:block;
width:15px;
}
button.btn:before
{
content:'-' ;
display:block;
width:15px;
}
Update 2 With pure Javascript
http://jsfiddle.net/WteTy/
function handleClick()
{
this.value = (this.value == '+' ? '-' : '+');
}
document.getElementById('collapsible').onclick=handleClick;

Here's another CSS only solution that works with any HTML layout.
It works with any element you need to switch. Whatever your toggle layout is you just put it inside a couple of elements with the if-collapsed and if-not-collapsed classes inside the toggle element.
The only catch is that you have to make sure you put the desired initial state of the toggle. If it's initially closed, then put a collapsed class on the toggle.
It also requires the :not selector, so it doesn't work on IE8.
HTML example:
<a class="btn btn-primary collapsed" data-toggle="collapse" href="#collapseExample">
<!--You can put any valid html inside these!-->
<span class="if-collapsed">Open</span>
<span class="if-not-collapsed">Close</span>
</a>
<div class="collapse" id="collapseExample">
<div class="well">
...
</div>
</div>
Less version:
[data-toggle="collapse"] {
&.collapsed .if-not-collapsed {
display: none;
}
&:not(.collapsed) .if-collapsed {
display: none;
}
}
CSS version:
[data-toggle="collapse"].collapsed .if-not-collapsed {
display: none;
}
[data-toggle="collapse"]:not(.collapsed) .if-collapsed {
display: none;
}
JS Fiddle

Add some jquery code, you need jquery to do this :
<script>
$(".btn[data-toggle='collapse']").click(function() {
if ($(this).text() == '+') {
$(this).text('-');
} else {
$(this).text('+');
}
});
</script>

All the other solutions posted here cause the toggle to get out of sync if it is double clicked. The following solution uses the events provided by the Bootstrap framework, and the toggle always matches the state of the collapsible element:
HTML:
<div class="row-fluid summary">
<div class="span11">
<h2>MyHeading</h2>
</div>
<div class="span1">
<button id="intro-switch" class="btn btn-success" data-toggle="collapse" data-target="#intro">+</button>
</div>
</div>
<div class="row-fluid summary">
<div id="intro" class="collapse">
Here comes the text...
</div>
</div>
JS:
$('#intro').on('show', function() {
$('#intro-switch').html('-')
})
$('#intro').on('hide', function() {
$('#intro-switch').html('+')
})
That should work for most cases.
However, I also ran into an additional problem when trying to nest one collapsible element and its toggle switch inside another collapsible element. With the above code, when I click the nested toggle to hide the nested collapsible element, the toggle for the parent element also changes. It may be a bug in Bootstrap. I found a solution that seems to work: I added a "collapsed" class to the toggle switches (Bootstrap adds this when the collapsible element is hidden but they don't start out with it), then added that to the jQuery selector for the hide function:
http://jsfiddle.net/fVpkm/87/
HTML:
<div class="row-fluid summary">
<div class="span11">
<h2>MyHeading</h2>
</div>
<div class="span1">
<button id="intro-switch" class="btn btn-success collapsed" data-toggle="collapse" data-target="#intro">+</button>
</div>
</div>
<div class="row-fluid summary">
<div id="intro" class="collapse">
Here comes the text...<br>
<a id="details-switch" class="collapsed" data-toggle="collapse" href="#details">Show details</a>
<div id="details" class="collapse">
More details...
</div>
</div>
</div>
JS:
$('#intro').on('show', function() {
$('#intro-switch').html('-')
})
$('#intro').on('hide', function() {
$('#intro-switch.collapsed').html('+')
})
$('#details').on('show', function() {
$('#details-switch').html('Hide details')
})
$('#details').on('hide', function() {
$('#details-switch.collapsed').html('Show details')
})

I liked the CSS-only solution from PSL, but in my case I needed to include some HTML in the button, and the content CSS property is showing the raw HTML with tags in this case.
In case that could help someone else, I've forked his fiddle to cover my use case: http://jsfiddle.net/brunoalla/99j11h40/2/
HTML:
<div class="row-fluid summary">
<div class="span11">
<h2>MyHeading</h2>
</div>
<div class="span1">
<button class="btn btn-success collapsed" data-toggle="collapse" data-target="#intro">
<span class="show-ctrl">
<i class="fa fa-chevron-down"></i> Expand
</span>
<span class="hide-ctrl">
<i class="fa fa-chevron-up"></i> Collapse
</span>
</button>
</div>
</div>
<div class="row-fluid summary">
<div id="intro" class="collapse">
Here comes the text...
</div>
</div>
CSS:
button.btn .show-ctrl{
display: none;
}
button.btn .hide-ctrl{
display: block;
}
button.btn.collapsed .show-ctrl{
display: block;
}
button.btn.collapsed .hide-ctrl{
display: none;
}

My following JS solution is better than the other approaches here because it ensures that it will always say 'open' when the target is closed, and vice versa.
HTML:
<a href="#collapseExample" class="btn btn-primary" data-toggle="collapse" data-toggle-secondary="Close">
Open
</a>
<div class="collapse" id="collapseExample">
<div class="well">
...
</div>
</div>
JS:
$('[data-toggle-secondary]').each(function() {
var $toggle = $(this);
var originalText = $toggle.text();
var secondaryText = $toggle.data('toggle-secondary');
var $target = $($toggle.attr('href'));
$target.on('show.bs.collapse hide.bs.collapse', function() {
if ($toggle.text() == originalText) {
$toggle.text(secondaryText);
} else {
$toggle.text(originalText);
}
});
});
Examples:
$('[data-toggle-secondary]').each(function() {
var $toggle = $(this);
var originalText = $toggle.text();
var secondaryText = $toggle.data('toggle-secondary');
var $target = $($toggle.attr('href'));
$target.on('show.bs.collapse hide.bs.collapse', function() {
if ($toggle.text() == originalText) {
$toggle.text(secondaryText);
} else {
$toggle.text(originalText);
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet"/>
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
<a href="#collapseExample" class="btn btn-primary" data-toggle="collapse" data-toggle-secondary="Close">
Open
</a>
<div class="collapse" id="collapseExample">
<div class="well">
...
</div>
</div>
JS Fiddle
Other benefits of this approach:
the code is DRY and reusable
each collapse button stays separate
you only need to put one change into the HTML: adding the data-toggle-secondary attribute

I guess you could look inside your downloaded code where exactly there is a + sign (but this might not be very easy).
What I'd do?
I'd find the class/id of the DOM elements that contain the + sign (suppose it's ".collapsible", and with Javascript (actually jQuery):
<script>
$(document).ready(function() {
var content=$(".collapsible").html().replace("+", "-");
$(".collapsible").html(content));
});
</script>
edit
Alright... Sorry I haven't looked at the bootstrap code... but I guess it works with something like slideToggle, or slideDown and slideUp... Imagine it's a slideToggle for the elements of class .collapsible, which reveal contents of some .info elements. Then:
$(".collapsible").click(function() {
var content=$(".collapsible").html();
if $(this).next().css("display") === "none") {
$(".collapsible").html(content.replace("+", "-"));
}
else $(".collapsible").html(content.replace("-", "+"));
});
This seems like the opposite thing to do, but since the actual animation runs in parallel, you will check css before animation, and that's why you need to check if it's visible (which will mean it will be hidden once the animation is complete) and then set the corresponding + or -.

Easier with inline coding
<button type="button" ng-click="showmore = (showmore !=null && showmore) ? false : true;" class="btn float-right" data-toggle="collapse" data-target="#moreoptions">
<span class="glyphicon" ng-class="showmore ? 'glyphicon-collapse-up': 'glyphicon-collapse-down'"></span>
{{ showmore !=null && showmore ? "Hide More Options" : "Show More Options" }}
</button>
<div id="moreoptions" class="collapse">Your Panel</div>

Some may take issue with changing the Bootstrap js (and perhaps validly so) but here is a two line approach to achieving this.
In bootstrap.js, look for the Collapse.prototype.show function and modify the this.$trigger call to add the html change as follows:
this.$trigger
.removeClass('collapsed')
.attr('aria-expanded', true)
.html('Collapse')
Likewise in the Collapse.prototype.hide function change it to
this.$trigger
.addClass('collapsed')
.attr('aria-expanded', false)
.html('Expand')
This will toggle the text between "Collapse" when everything is expanded and "Expand" when everything is collapsed.
Two lines. Done.
EDIT: longterm this won't work. bootstrap.js is part of a Nuget package so I don't think it was propogating my change to the server. As mentioned previously, not best practice anyway to edit bootstrap.js, so I implemented PSL's solution which worked great. Nonetheless, my solution will work locally if you need something quick just to try it out.

You do like this.
the function return the old text.
$('button').click(function(){
$(this).text(function(i,old){
return old=='Read More' ? 'Read Less' : 'Read More';
});
});

Applied and working in Bootstrap 5.0.1.
Using simple jQuery
jQuery('button').on( 'click', function(){
if(jQuery(this).hasClass('collapsed')){
jQuery(this).html('+');
} else {
jQuery(this).html('-');
}
});
You can also use font awesome or HTML instead of +/- signs.

Related

How do I toggle a class in Angular

I have a button that I want to be able to toggle a class on a div to hide and show the div how would I do that in Angular?
HTML
<div id="chatsidebar">
<app-chatsidebar></app-chatsidebar>
</div>
<div>
<button type="button" id="sidebarCollapse" class="btn btn-info" (click)="togglesideBar()">
<i class="glyphicon glyphicon-align-right"></i>
Toggle Sidebar
</button>
</div>
I want to add the class "active" onto the #chatsidebar div
app.component.ts
togglesideBar() {
}
Thanks
I'm answering this part of your question:
I want to add the class "active" onto the #chatsidebar div
To do it, you can use NgClass. NgClass allows you to add or remove any class to or from an element based on the given condition. Your code will looks something like this:
HTML
<div id="chatsidebar" [ngClass]="{'active': isSideBarActive}"> <!-- this ngClass will add or remove `active` class based on the `isSideBarActive` value -->
<app-chatsidebar></app-chatsidebar>
</div>
<div>
<button type="button" id="sidebarCollapse" class="btn btn-info" (click)="togglesideBar()">
<i class="glyphicon glyphicon-align-right"></i>
Toggle Sidebar
</button>
</div>
Component
isSideBarActive: boolean = true; // initial value can be set to either `false` or `true`, depends on our need
togglesideBar() {
this.isSideBarActive = !this.isSideBarActive;
}
HTML
<div id="chatsidebar" *ngIf="status">
<app-chatsidebar></app-chatsidebar>
</div>
<div>
<button type="button" id="sidebarCollapse" class="btn btn-info" (click)="togglesideBar()">
<i class="glyphicon glyphicon-align-right"></i>
Toggle Sidebar
</button>
</div>
app.component.ts:
status:boolean=true;
togglesideBar() {
if(this.status == true) this.status=false;
else this.status = true;
}
Demo:
https://plnkr.co/edit/fNoXWhUhMaUoeMihbGYd?p=preview
you can try below.
<div id="chatsidebar" class="{{activeClass}}"> ... </div>
and on your component define a property and set the class value on toggle function
// On Component
activeClass : string = "";
...
togglesideBar() {
this.activeClass = 'active'
}
it shall work, but may not the ideal solution.
Assuming you have a class named hide:
<div [class.hide]="hide">
<app-chatsidebar></app-chatsidebar>
</div>
<div>
<button type="button" class="btn btn-info" (click)="togglesideBar()">
<i class="glyphicon glyphicon-align-right"></i>
Toggle Sidebar
</button>
</div>
togglesideBar() { this.hide = !this.hide; }
This will hide the element in question, while leaving it in the DOM. The other solutions using *ngIf will add and remove the element to and from the DOM. There are subtle reasons in specific cases to prefer one over the other, well described in the on-line documentation you have already read. In this case, it doesn't really matter.
The [class.className]=boolean format is just one of several ways to control classes in Angular. For instance, you could also have said:
[ngClass]="{'hide': hide}"
This is slightly more flexible because you can add/remove multiple classes at once.
Since you are using glyphicons, you are probably using Bootstrap, so you most likely already have the hide class defined.
As an aside, you rarely need IDs, and using them is pretty much of an anti-pattern in Angular.
Take a variable in your component something like
isShowChatSidebar:boolean=true;
then modify your method and html
togglesideBar() {
this.isShowChatSidebar=!this.isShowChatSidebar
}
<div id="chatsidebar" [ngClass]="{'active': isShowChatSidebar}">>
<app-chatsidebar></app-chatsidebar>
</div>

Expand/Collapse several blocks at the same time?

I have several blocks in my page. I use bootstrap 4 alpha 6 version. I want expand/collapse these blocks by clicking one button. Right know I use next js code and it only open all blocks but how to close them?! How to fix this problem?
HTML:
<div class="card">
<div class="card-header">
<button id='expand-collapse' type="button" data-parent="#blocks" data-toggle="collapse" data-target=".block" aria-expanded="false" aria-controls=".block">
</button>
</div>
<div class="card-block">
<div id="blocks">
<div class="list-group">
<div class="list-group-item">
<a data-toggle="collapse" href="#block-1" aria-expanded="false" aria-controls="block-1"OPEN FIRST</a>
<div class="collapse block" id="block-1">
<!--FIRST BLOCK BLOCK-->
</div>
</div>
<div class="list-group-item">
<a data-toggle="collapse" href="#block-2" aria-expanded="false" aria-controls="block-2">OPEN SECOND</a>
<div class="collapse block" id="block-2">
<!--SECOND BLOCK-->
</div>
</div>
<div class="list-group-item">
<a data-toggle="collapse" href="#block-3" aria-expanded="false" aria-controls="block-3">OPEN THIRD</a>
<div class="collapse block" id="block-3">
<!--THIRD BLOCK-->
</div>
</div>
</div>
</div>
</div>
</div>
JAVASCRIPT:
$(function() {
$('#expand-collapse').on('click', function() { // We capture the click event
var target = $(this).attr('data-target'); // We get teh target element selector
$(target).each(function() { // Loop through each element
if ($(this).hasClass('show')) { // Check if it's already visible or not
$(this).collapse('hide'); // Show and hide accordingly
} else {
$(this).collapse('show');
}
});
});
});
$(document).ready(function () {
$('.collapse')
.on('shown.bs.collapse', function(event) {
event.stopPropagation();
$(this)
.parent().parent()
.find(".fa-commenting-o")
.removeClass("fa-commenting-o")
.addClass("fa-commenting");
}).on('hidden.bs.collapse', function(event) {
event.stopPropagation();
$(this)
.parent().parent()
.find(".fa-commenting")
.removeClass("fa-commenting")
.addClass("fa-commenting-o");
});
});
The code that youve used will work as expected in bootstrap3 due to the way collapse was handled then (You can verify it by using JS & CSS of bootstrap V3)
Comming to solving your problem the following snippet would work as expected:
$(function() {
$('#expand-collapse').on('click', function() { // We capture the click event
var target = $(this).attr('data-target'); // We get teh target element selector
$(target).each(function() { // Loop through each element
if ($(this).hasClass('show')) { // Check if it's already visible or not
$(this).collapse('hide'); // Show and hide accordingly
} else {
$(this).collapse('show');
}
});
});
});
TIP:
We can also pass toggle argument to the collapse function and get rid of the if-else condition
$(this).collapse('toggle'); can be used to replace the if-else
But I did not use this in my example to show that you can add additional computation in it
Working Fiddle
UPDATE:
The updated question asks for individual control for the block
To acheive that, we can use the default method of triggering the action with a button element.
<div class="list-group-item">
<div class="collapse block" id="block-1">
FIRST BLOCK
</div>
</div>
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#block-1">
Block 1
</button>
You can find the updated jsFidde here
Add an else statement to handle all other cases that don't match the criteria to show. Try this:
$(function () {
$('#expand-collapse').on('click',function(){
$('[data-toggle="collapse"]').each(function(){
var objectID=$(this).attr('data-target');
if($(objectID).hasClass('.collapse')===false)
{
$(objectID).collapse('show');
} else {
$(objectID).collapse('hide');
}
});
});
});
There is an error with the Bootstrap v4.0.0-alpha.6 version with the transitioning that will be solved on the next release.
See the issue 22256 and pull 21743 links for more information.

Bootstrap collapse function difference between bootstrap v3.3.5 and v2.1.1

I am using bootstrap v3.3.5 in my application and wanted to include collapse function such that, when user clicks on a link, div below it toggles. Referring to answer in this Can you specify a "data-target" for Bootstrap which refers to a sibling DOM element without using an ID? I was able to achieve similar result as my requirement, in the below fiddle link
https://jsfiddle.net/szp1cg0k/, which is using bootstrap v2.1.1.min.js and v2.1.1.min.css
But in the same fiddle when I include bootstrap v3.3.5.min.js and v3.3.5.min.css reference the toggle/collapse functionality doesn't work here, neither throws any error
updated JS https://jsfiddle.net/ohoLxap6/2/
html code:
<fieldset class="fsStyle">
<legend class="legendStyle">
<a data-toggle="collapse-next" data-target=".demo" href="#">Activity Log Filter Criteria4</a>
</legend>
<div class="demo" >
<div class="col-md-2">
<label for="activity_from_date" class="labelStyle">Activity From Date:</label>
</div>
<div class="col-md-4">
<input name="fromDate" maxlength="10" size="11" tabindex="59" value="" onblur="javascript:DateFormat(this,event,true);" class="textInput" id="activity_from_date" type="text">
</div>
</div>
</fieldset>
script:
$('body').on('click.collapse-next.data-api', '[data-toggle=collapse-next]', function() {
console.log($(this).parent());
var $target = $(this).parent().next()
console.log($target);
$target.data('collapse') ? $target.collapse('toggle') : $target.collapse()
});
Can anyone give me some hint where I am going wrong ?
UPDATE:
I am aware of the collapse function of bootstrap, I have multiple divs in my form and I want to include collapse function on most of the divs. One way to achieve this is
<div data-toggle="collapse" data-target="#demo1">
<div id="demo1">
<p>demo 1 ......</p>
</div>
<div data-toggle="collapse" data-target="#demo2">
<div id="demo2">
<p>demo 2 ......</p>
</div>
But I dont want to use ids, instead I want to specify class. The reason being, I have jqtree at backend and I have to include clone function as well, so using ids would mean after cloning I need to take care of ids of cloned child node div. Hence want to use class instead , something like below
<div data-toggle="collapse" data-target=".demo">
<div class="demo">
<p>demo 1 ......</p>
</div>
<div data-toggle="collapse" data-target=".demo">
<div class="demo">
<p>demo 2 ......</p>
</div>
Got this working. I have updated the fiddle accordingly. https://jsfiddle.net/ohoLxap6/3/
$('body').on('click.collapse-next.data-api', '[data-toggle=collapse-next]',
function() {
//console.log($(this).parent());
var $target = $(this).parent().next()
console.log($target);
$target.data('bs.collapse') ? $target.collapse('toggle') :
$target.collapse()
});
Why would you write your own code for a existing Bootstrap function? Following code is an example of the latest Bootstrap version collapse method:
<button class="btn" data-toggle="collapse" data-target="#demo">Collapsible</button>
<div id="demo" class="collapse">
Some text..
</div>
Docs: http://getbootstrap.com/javascript/#collapse
UPDATE:
According to your new question, collapsing using classes, I have created a custom script:
$('[data-toggle="collapse"]').click(function() {
var $target = $(this).data('target');
var $target = $($target);
$target.data('bs.collapse') ? $target.collapse('toggle') :
$target.collapse()
});
Now all classes inside the data-target attribute will get toggled. https://jsfiddle.net/ohoLxap6/4/

Hide/Show many elements on single click by jQuery

I've code few line of jQuery for Hide/Show many elements on single click and it's working. But problem is; i've many more image class items, so my script going to long, my question is how to simplify or make short my script, i mean any alternatives or any new idea? please suggest.
HTML:
<div id="choose-color">
<span>
<i class="images-red" style="">Red Image</i>
<i class="images-blue" style="display: none;">Blue Image</i>
<i class="images-pink" style="display: none;">Pink Image</i>
<!-- many many images -->
</span>
<button class="red">Red</button>
<button class="blue">Blue</button>
<button class="pink">Pink</button>
</div>
JS: live demo >
$("button.red").click(function(){
$(".images-red").show();
$(".images-blue, .images-pink").hide();
});
$("button.blue").click(function(){
$(".images-red, .images-pink").hide();
$(".images-blue").show();
});
$("button.pink").click(function(){
$(".images-red, .images-blue").hide();
$(".images-pink").show();
});
Please suggest for short and simple code of my script. Thanks.
You can do it by adding just a common class to those buttons,
var iTags = $("#choose-color span i");
$("#choose-color button.button").click(function(){
iTags.hide().eq($(this).index("button.button")).show();
});
The concept behind the code is to bind click event for the buttons by using the common class. Now inside the event handler, hide all the i elements which has been cached already and show the one which has the same index as clicked button.
DEMO
For more details : .eq() and .index(selector)
And if your elements order are not same, both the i and button's. Then you can use the dataset feature of javascript to over come that issue.
var iTags = $("#choose-color span i");
$("#choose-color button.button").click(function(){
iTags.hide().filter(".images-" + this.dataset.class).show()
});
For implementing this you have to add data attribute to your buttons like,
<button data-class="red" class="button red">Red</button>
DEMO
This works
$("#choose-color button").click(function(){
var _class = $(this).attr('class');
$("#choose-color i").hide();
$(".images-"+_class).show();
});
https://jsfiddle.net/455k1hhh/5/
I know this might not be the prettiest solution, but it should do the job.
$("button").click(function(){
var classname = $(this).attr('class');
$("#choose-color span i").hide();
$(".images-"+classname).show();
});
You're making future extensibility a little difficult this way due to relying on class names but this would solve your immediate need:
<div id="myImages">
<i class="images-red" style="">Red Image</i>
<i class="images-blue" style="display: none;">Blue Image</i>
<i class="images-pink" style="display: none;">Pink Image</i>
<!-- Many many image -->
</div>
<div id="myButtons">
<button class="red">Red</button>
<button class="blue">Blue</button>
<button class="pink">Pink</button>
</div>
$("#myButtons button").click(function(){
var color = $(this).attr("class");
var imageClass = ".images-"+color;
$('#myImages').children("i").each(function () {
$(this).hide();
});
$(imageClass).show();
});
Here's a JSFiddle
Edit: Note how I wrapped the buttons and images in parent divs to allow you to isolate just the buttons/images you want to work with.
You can do the following using data-* attributes, because when you have more elements of the same color, using index of the button won't work. And simply using the whole class attribute won't work if you have to add more classes to the button in future.
$("button").click(function() {
var color = $(this).data('color');
var targets = $('.images-' + color);
targets.show();
$("span i").not(targets).hide();
});
.hidden {
display: none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<br/>
<br/>
<div id="choose-color">
<span>
<i class="images-red">Red Image</i>
<i class="images-blue hidden">Blue Image</i>
<i class="images-pink hidden">Pink Image</i>
<!-- Many many image -->
</span>
<br/>
<br/>
<button data-color="red">Red</button>
<button data-color="blue">Blue</button>
<button data-color="pink">Pink</button>
</div>
It would make sense to have all images share a single class (.image for example). Then you just use a shared class for the button and the image; in this example I used the color name. Now, when any button is clicked, you can grab the class name of the image you want to show.
Give this a try:
$("button").click(function(){
$(".image").hide();
var className = $(this).attr("class");
$("." + className).show();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<br/><br/>
<div id="choose-color">
<span>
<i class="image red" style="">Red Image</i>
<i class="image blue" style="display: none;">Blue Image</i>
<i class="image pink" style="display: none;">Pink Image</i>
<!-- Many many image -->
</span>
<br/><br/>
<button class="red">Red</button>
<button class="blue">Blue</button>
<button class="pink">Pink</button>
</div>
You may try this:
<div id="choose-color">
<span>
<i class="images-red" style="">Red Image</i>
<i class="images-blue" style="display: none;">Blue Image</i>
<i class="images-pink" style="display: none;">Pink Image</i>
<!-- Many image -->
</span>
<br/><br/>
<button class="colour red" onclick="myFunction(this)">Red</button>
<button class="colour blue" onclick="myFunction(this)">Blue</button>
<button class="colour pink" onclick="myFunction(this)">Pink</button>
</div>
JS: see here
$(".colour").click(function(){
var colors = ["red", "blue", "pink"];
for (i = 0; i < colors.length; i++) {
if($(this).hasClass(colors[i])){
$(".images-"+colors[i]).show();
}else{
$(".images-"+colors[i]).hide();
}
}
});

Factorize use of repeated similar div blocks with javascript

I'm building an app with html/javascript.
I feel my code could be made cleaner and factorized with some javascript but don't know how to find this code (while keeping a very efficient page load performance).
<div id="deal-zone">
<div class="deal">
<span class="beamer" data-toggle="modal" data-target="#myModal"/></span>
</div>
<div class="deal">
<span class="beamer" data-toggle="modal" data-target="#myModal"></span>
</div>
<div class="deal">
<span class="beamer" data-toggle="modal" data-target="#myModal"></span>
</div>
<div class="deal">
<span class="beamer" data-toggle="modal" data-target="#myModal"></span>
</div>
<div class="deal" >
<span class="beamer" data-toggle="modal" data-target="#myModal"></span>
</div>
<div class="deal" >
<span class="beamer" data-toggle="modal" data-target="#myModal"></span>
</div>
<div class="deal">
<span class="beamer" data-toggle="modal" data-target="#myModal"></span>
</div>
<div class="deal">
<span class="beamer" data-toggle="modal" data-target="#myModal"></span>
</div>
<div class="deal">
<span class="beamer" data-toggle="modal" data-target="#myModal"></span>
</div>
<div class="deal">
<span class="beamer" data-toggle="modal" data-target="#myModal"></span>
</div>
</div>
As you see it's really very very repetitive as I have 10 times the exact same block.
What I am trying to do is simply something like this and i lack the javascript chops for it:
function(){display in the html make 10 times repeatedly
<div class="deal">
<span class="beamer" data-toggle="modal" data-target="#myModal"></span>
</div>
}
Note: if you wonder by the way, javascript is dynamically giving each a certain position on the page.
$(document).ready(function(){
function getRandomInt(min, max) {
return Math.random() * (max - min + 1) + min;
}
$(".deal").each(function () {
var topPosition = getRandomInt(8, 70);
var leftPosition = getRandomInt(8, 92);
$(this).css({
"top": topPosition+"%",
"left": leftPosition+"%",
});
});
});
How can I do this ?
Here are some tips that might you.
If you want to use jQuery to generate the HTML for you, you can do the following:
var numBlocks = 10;
var $dealZone = $("#deal-zone");
var $toAppend = $('<div class="deal"><span class="beamer" data-toggle="modal" data-target="#myModal"></span></div>');
for(var c = 0; c < numBlocks; c++)
$dealZone.append($toAppend.clone());
JSFiddle to demonstrate (used <li>, sorry)
However, I just want to point out, that is not a great SEO way to do things. Dynamic HTML is not picked up so well by Search Engine crawlers, so it would look to the Search Engines that your content was missing.
Your first <span> tag has a closing slash. This is not valid HTML. Should be:
data-target="#myModal">
and not
data-target="#myModal"/>
It looks like your HTML is a list of some sort. Semantically, you might want to consider using a list structure with <ul> and <li> tags. You can still style these to remove the padding, margin, and bullets to display them any way you would like.
To simplify CSS classes, (using your current HTML) you could remove the class="deal" and class="beamer" from every child element. If you need this class for CSS styling, you can use the descendant selector (which targets all immediate children of the parent) as follows:
#deal-zone > div { /*styles here*/ } /* targets the current "deal" class */
#deal-zone > div > span { /*styles here*/ } /* targets the current ".beamer" class */
You could also use the descendant selector in your jQuery function. Use the following JavaScript to target the children without having the "deal" class:
$("#deal-zone > div").each(function () { ... }
In addition, you most likely don't need the repetitive data-toggle and data-target attributes on all of the children. Since they are all the same, you can assign these attributes to the parent and access them with the following jQuery:
var $dealZone = $('#deal-zone');
var data-toggle = $dealZone.attr('data-toggle');
var data-target = $dealZone.attr('data-target');
In summary, here is a working example in JSFiddle

Categories