2
\$\begingroup\$

This code I written by myself. Here I have 3 main part. When I click on any main part then it sub part will appear. Sub part contain some check boxes. Here I have the following main functionality

  1. Click the main part, then show it's sub part.If sub part already displayed then hide the sub part
  2. Highlight selected main part
  3. At a time only highlight one main part and it's child
  4. When the the checkbox div inside the sub part is clicked anywhere then the checkbox need to check and highlight that part

Hint:

Main part ( class: filter-3)

Sub Part (class: filter-option-output)

Sub part div (class: common-in-block)

Please see my code

	$(function(){
	  $(".filter-section-color").on("click",function(){
	         
			 $(".filter-section-pattern").removeClass("output-active");
			 $(".filter-section-room").removeClass("output-active");
			
			 
		   
		   if ( $( this ).hasClass( "output-active" ) ) {  
             $(".filter-option-output").css("display","none");
			  $(this).removeClass("output-active");
		   }
		   else{
			 $(".filter-option-output").css("display","none");
			 $(".color-output").toggle();
			 $(this).addClass("output-active");
			
		 }
	  
	  });
	  
	  $(".filter-section-pattern").on("click",function(){
	      
		  $(".filter-section-color").removeClass("output-active");
		  $(".filter-section-room").removeClass("output-active");
		
	  
	     if ( $( this ).hasClass( "output-active" ) ) {  
              $(".filter-option-output").css("display","none");
			  $(this).removeClass("output-active");
		   }
	    else{
			 $(".filter-option-output").css("display","none");
			 $(".pattern-output").toggle();
			 $(this).addClass("output-active");
			
		 }
	  
	  });
	  
	  $(".filter-section-room").on("click",function(){
	      
		  $(".filter-section-pattern").removeClass("output-active");
	      $(".filter-section-color").removeClass("output-active");
		  
		  
		  if ( $( this ).hasClass( "output-active" ) ) {  
              $(".filter-option-output").css("display","none");
			  $(this).removeClass("output-active");
		   }
	    else{
			 $(".filter-option-output").css("display","none");
			 $(".room-output").toggle();
			 $(this).addClass("output-active");
			
		 }
	  
	  });
	  
	  $(".color-box").on("click",function(){
	     $(".color-box").removeClass("active-box");
	     $(this).addClass("active-box");
		 var checkbox1 =  $(this).find("input[type='checkbox']");
		   if(checkbox1.is(':checked')){ 
		              checkbox1.prop('checked','');
				      $(this).removeClass("active-box"); 
		      }
		   else{   checkbox1.prop('checked','true'); }
		 });
		 
	  
	   $(".pattern-box").on("click",function(){
	     $(".pattern-box").removeClass("active-box");
	     $(this).addClass("active-box");
		 var checkbox2 =  $(this).find("input[type='checkbox']");
		  if(checkbox2.is(':checked')){ 
		              checkbox2.prop('checked','');
				      $(this).removeClass("active-box"); 
		      }
		   else{   checkbox2.prop('checked','true'); }
		 
		
	  });
	  
	   $(".room-box").on("click",function(){
	     $(".room-box").removeClass("active-box");
	     $(this).addClass("active-box");
		 var checkbox3 =  $(this).find("input[type='checkbox']");
		  if(checkbox3.is(':checked')){ 
		              checkbox3.prop('checked','');
				      $(this).removeClass("active-box"); 
		      }
		   else{   checkbox3.prop('checked','true'); }
		  
	  });
	  
	});
	
body{
background-color: #d6e9d880 !important;
}
.filter-section-p{
	
	margin-bottom: 8px;
}
.filter-arrow{
	margin-top: 5px;
    float: right;
}

.filter-section{
	background: #E5E5E599;
	text-align:center;
	padding-top: 18px !important;
	padding-bottom: 41px;
}

.filter-section-h2{
	margin-bottom: 2px !important;
	font-size: 24px;
	text-transform: uppercase;
}

.filter-icon{
	width:35px;
	float:left;

}
.filter-inside-p{
	float:left;
	text-transform: uppercase;
    font-size: 16px;
    margin-left: 15px;
	margin-bottom: 0px;

}

.filter-3{
	border:1px solid #912C5E33;
	float:left;
	width:27%;
	margin-left: 3%;
	padding: 6px;
	cursor:pointer;
}

.filter-main-div{
	margin-left: 49px;
	margin-bottom:3px;
}
.filter-option-output{
	border-left: 1px solid #93A8B733;
	border-right: 1px solid #93A8B733;
	background: white;
	position: absolute;
	margin-top: 58px;
	z-index: 3;
	display:none;
}

.color-backround{
	float:left;
	min-width: 47px;
    height: 32px;
}
.color-name{
	margin-left: 12px !important;
	font-size: 14px !important;
	text-transform: uppercase !important;
	margin-top: 4px !important;
	float:left !important;
	margin-bottom: 15px;
}
.color-value{
	float: right !important;
	margin-top: 11px !important;
	margin-right: 13px !important;
}
.common-in-block{
	float:left;
	width:30%;
	margin-left: 3%;
	padding-top: 11px;
	border-right: 1px solid #80808033;
	padding-bottom: 0px !important;
	cursor:pointer;
}

.output-active{ background:white !important; border:2px solid #912C5E33 !important; }
.color-block { border-bottom: 1px solid #80808033; overflow: hidden; padding-bottom: 4px; margin-top:4px; }
.active-box { background:#f5deb380; }

.color-black{ background-color:#252525; }
.color-blue{ background-color:#99CEE8; }
.color-brown{ background-color:#96776B; }
.color-cream{ background-color:#EAE3D9; }
.color-green{ background-color:#BED6A4; }
.color-grey{ background-color:#919191; }
.color-orange{ background-color:#FF9D78; }
.color-pink{ background-color:#F9C5CA; }
.color-purple{ background-color:#AF9EC7; }
.color-red{ background-color:#E95A63; }
.color-silver{ background-color:#DDDDDD; }
.color-white{ background-color:#F8F8F8; }
<html>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<body>
				                
	<div class=" col-sm-12 filter-main-div"> 
								
		<div class="col-sm-8 filter-main">
				                   
		 <div class="filter-3 filter-section-color">
			 <img src="https://image.flaticon.com/icons/svg/401/401122.svg" class="filter-icon" />
		  <p class="filter-inside-p"> Part1</p> 
			 <i class="icon-chevron-down filter-arrow"></i>
		</div>
							 
		<div class="filter-3 filter-section-pattern">
			<img src="https://image.flaticon.com/icons/svg/401/401122.svg" class="filter-icon" />
			<p class="filter-inside-p">Part2</p> 
			<i class="icon-chevron-down filter-arrow"></i>
		</div>
								
		<div class="filter-3 filter-section-room">
				<img src="https://image.flaticon.com/icons/svg/401/401122.svg"  class="filter-icon"/>
			<p class="filter-inside-p">Part3</p> 
			<i class="icon-chevron-down filter-arrow"></i>
		</div>
								 
	</div> 
								
	<div class="col-sm-8 filter-option-output color-output">
								
		<div class="color-block">
			<div class="common-in-block color-box">
				 <div class="color-backround color-cream">&nbsp;</div><p class="color-name">Part1-child1</p>
				<input type="checkbox" value="cream" class="color-value">
				</div>
				<div class="common-in-block color-box">
				<div class="color-backround color-green">&nbsp;</div><p class="color-name">Part1-child2</p>
					 <input type="checkbox" value="green" class="color-value">
			</div>
				<div class="common-in-block color-box">
						 <div class="color-backround color-grey">&nbsp;</div><p class="color-name">Part1-child3</p>
						<input type="checkbox" value="grey" class="color-value">
						 </div>
						</div>
								     
				</div>
							
							
				<div class="col-sm-8 filter-option-output pattern-output">
					<div class="color-block">
					<div class="common-in-block pattern-box">
					<div class="color-backround color-black">&nbsp;</div><p class="color-name">Part-2-child1</p>
					 <input type="checkbox" value="black" class="color-value">
					 </div>
				 <div class="common-in-block pattern-box">
				<div class="color-backround color-blue">&nbsp;</div><p class="color-name">Part-2-child2</p>
					<input type="checkbox" value="blue" class="color-value">
									   </div>
				 <div class="common-in-block pattern-box">
					<div class="color-backround color-red">&nbsp;</div><p class="color-name">Part-2-child3</p>
					 <input type="checkbox" value="brown" class="color-value">
					 </div>
					 </div>
						</div>
								
			<div class="col-sm-8 filter-option-output room-output">
				<div class="color-block">
					<div class="common-in-block room-box">
					<div class="color-backround color-black">&nbsp;</div><p class="color-name">Part#3-child1</p>
					<input type="checkbox" value="black" class="color-value">
					 </div>
					 <div class="common-in-block room-box">
				<div class="color-backround color-blue">&nbsp;</div><p class="color-name">Part#3-child2</p>
				<input type="checkbox" value="blue" class="color-value">
				  </div>
				<div class="common-in-block room-box">
					 <div class="color-backround color-red">&nbsp;</div><p class="color-name">Part#3-child3</p>
						<input type="checkbox" value="brown" class="color-value">
						 </div>
				</div>
			</div>
								
 </div>
       </body>
       </html>
       
       

Please copy this code into your localhost and check it.

Here all of my functionality is working perfectly. But what I feel that the logic I applied is not that much good and still I can reduce the code. Please check this code and suggest which part I can still reduce the code.

\$\endgroup\$
  • \$\begingroup\$ I don't know if I'd use the word "perfectly." After clicking around a little bit, all the check boxes became unresponsive (they registered the clicks, but would not check/uncheck). \$\endgroup\$ – Jared Goguen May 5 '17 at 16:37
1
\$\begingroup\$

As said by konijn in his answer, hasClass -> add/remove class can be replaced by toggleClass().

if ($(selector).hasClass('someClass')) {
    $(selector).removeClass('someClass');
} else {
    $(selector).addClass('someClass');
}

can be replaced by

$(selector).toggleClass('someClass');

The code, $(".someClass").css("display","none"); is in both if and else block in all three functions. This can be moved outside of them. Also, I'll suggest to use hide() instead of applying CSS explicitly as it is more expressive and easy to understand.

$('someSelector').hide();

The code to remove class

$(".filter-section-pattern").removeClass("output-active");
$(".filter-section-room").removeClass("output-active");

can be written by combining selectors as

$(".filter-section-pattern, .filter-section-room").removeClass("output-active");

jQuery will take care of iterating over elements matched by selector and do appropriate action, removeClass in this case.


Now, if you look at the first three event handlers, you'll see that they all are similar.

  1. Remove some class from some elements
  2. Toggle some class on clicked element
  3. Hide some element
  4. Toggle some element depending on a condition

Can we make this code dynamic? To make it dynamic, we need to first check what all things are different in them and by accessing them dynamically these three functions can be combined.

First, we need to add some custom attributes on element on which event is bound. To take example, I'll use below element

<div class="filter-3 filter-section-color">

We'll add custom HTML5 data-* attribute on it to store custom information

<div class="filter-3 filter-section-color" data-selector=".filter-section-pattern, .filter-section-room">

Here, we're adding CSS selectors as it is which are to be hide when this element is clicked. To access this from JavaScript when clicked data() can be used

$(this).data('selector')

Note that $(this) inside event handler refer to the element on which the event has occurred.

We're ready!!! Now, to bind event on all three elements, we'll pass them as comma-separated list of selectors just how we use in CSS.

Here's the code of the first three event handlers

// Bind event on all the elements
$(".filter-section-color, .filter-section-pattern, .filter-section-room").on("click", function() {

    // Hide
    $(".filter-option-output").hide();
    // Get target selector and remove class
    $($(this).data("selector")).removeClass("output-active");

    if ($(this).hasClass("output-active") === false) {
        $($(this).data('targetSelector')).toggle();
    }

    // Toggle class on clicked element
    $(this).toggleClass("output-active");
});

Similarly, the last three event handlers can also be combined

// Bind event on all elements
$(".color-box, .pattern-box, .room-box").on("click", function() {
    // Dynamic
    $("." + $(this).data("myClass")).removeClass("active-box");
    var $checkbox = $(this).find("input[type='checkbox']");
    $checkbox.prop('checked', !$checkbox.is(':checked'));
    $(this).toggleClass("active-box", !$checkbox.is(':checked'));
});

This also requires changes in HTML of elements on which event is bound. As can be seen from the code, data-my-class custom attribute should be added with value as same class.

Example, <div class="common-in-block color-box"> on this element adding custom attribute will be <div class="common-in-block color-box" data-my-class="color-box">. This is required as there can be multiple classes on element and taking a particular class can be cumbersome or long if...else if trail.

$(document).ready(function() {
  $(".filter-section-color, .filter-section-pattern, .filter-section-room").on("click", function() {
    $(".filter-option-output").hide();
    $($(this).data("selector")).removeClass("output-active");

    if ($(this).hasClass("output-active") === false) {
      $($(this).data('targetSelector')).toggle();
    }

    $(this).toggleClass("output-active");
  });

  $(".color-box, .pattern-box, .room-box").on("click", function() {
    $("." + $(this).data("myClass")).removeClass("active-box");
    var $checkbox = $(this).find("input[type='checkbox']");
    $checkbox.prop('checked', !$checkbox.is(':checked'));
    $(this).toggleClass("active-box", !$checkbox.is(':checked'));
  });
});
body {
  background-color: #d6e9d880 !important;
}

.filter-section-p {
  margin-bottom: 8px;
}

.filter-arrow {
  margin-top: 5px;
  float: right;
}

.filter-section {
  background: #E5E5E599;
  text-align: center;
  padding-top: 18px !important;
  padding-bottom: 41px;
}

.filter-section-h2 {
  margin-bottom: 2px !important;
  font-size: 24px;
  text-transform: uppercase;
}

.filter-icon {
  width: 35px;
  float: left;
}

.filter-inside-p {
  float: left;
  text-transform: uppercase;
  font-size: 16px;
  margin-left: 15px;
  margin-bottom: 0px;
}

.filter-3 {
  border: 1px solid #912C5E33;
  float: left;
  width: 27%;
  margin-left: 3%;
  padding: 6px;
  cursor: pointer;
}

.filter-main-div {
  margin-left: 49px;
  margin-bottom: 3px;
}

.filter-option-output {
  border-left: 1px solid #93A8B733;
  border-right: 1px solid #93A8B733;
  background: white;
  position: absolute;
  margin-top: 58px;
  z-index: 3;
  display: none;
}

.color-backround {
  float: left;
  min-width: 47px;
  height: 32px;
}

.color-name {
  margin-left: 12px !important;
  font-size: 14px !important;
  text-transform: uppercase !important;
  margin-top: 4px !important;
  float: left !important;
  margin-bottom: 15px;
}

.color-value {
  float: right !important;
  margin-top: 11px !important;
  margin-right: 13px !important;
}

.common-in-block {
  float: left;
  width: 30%;
  margin-left: 3%;
  padding-top: 11px;
  border-right: 1px solid #80808033;
  padding-bottom: 0px !important;
  cursor: pointer;
}

.output-active {
  background: white !important;
  border: 2px solid #912C5E33 !important;
}

.color-block {
  border-bottom: 1px solid #80808033;
  overflow: hidden;
  padding-bottom: 4px;
  margin-top: 4px;
}

.active-box {
  background: #f5deb380;
}

.color-black {
  background-color: #252525;
}

.color-blue {
  background-color: #99CEE8;
}

.color-brown {
  background-color: #96776B;
}

.color-cream {
  background-color: #EAE3D9;
}

.color-green {
  background-color: #BED6A4;
}

.color-grey {
  background-color: #919191;
}

.color-orange {
  background-color: #FF9D78;
}

.color-pink {
  background-color: #F9C5CA;
}

.color-purple {
  background-color: #AF9EC7;
}

.color-red {
  background-color: #E95A63;
}

.color-silver {
  background-color: #DDDDDD;
}

.color-white {
  background-color: #F8F8F8;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>


<div class=" col-sm-12 filter-main-div">

  <div class="col-sm-8 filter-main">

    <div class="filter-3 filter-section-color" data-selector=".filter-section-pattern, .filter-section-room" data-target-selector=".color-output">
      <img src="https://image.flaticon.com/icons/svg/401/401122.svg" class="filter-icon" />
      <p class="filter-inside-p"> Part1</p>
      <i class="icon-chevron-down filter-arrow"></i>
    </div>

    <div class="filter-3 filter-section-pattern" data-selector=".filter-section-color, .filter-section-room" data-target-selector=".pattern-output">
      <img src="https://image.flaticon.com/icons/svg/401/401122.svg" class="filter-icon" />
      <p class="filter-inside-p">Part2</p>
      <i class="icon-chevron-down filter-arrow"></i>
    </div>

    <div class="filter-3 filter-section-room" data-selector=".filter-section-color, .filter-section-pattern" data-target-selector=".room-output">
      <img src="https://image.flaticon.com/icons/svg/401/401122.svg" class="filter-icon" />
      <p class="filter-inside-p">Part3</p>
      <i class="icon-chevron-down filter-arrow"></i>
    </div>

  </div>

  <div class="col-sm-8 filter-option-output color-output">

    <div class="color-block">
      <div class="common-in-block color-box" data-my-class="color-box">
        <div class="color-backround color-cream">&nbsp;</div>
        <p class="color-name">Part1-child1</p>
        <input type="checkbox" value="cream" class="color-value">
      </div>
      <div class="common-in-block color-box" data-my-class="color-box">
        <div class="color-backround color-green">&nbsp;</div>
        <p class="color-name">Part1-child2</p>
        <input type="checkbox" value="green" class="color-value">
      </div>
      <div class="common-in-block color-box" data-my-class="color-box">
        <div class="color-backround color-grey">&nbsp;</div>
        <p class="color-name">Part1-child3</p>
        <input type="checkbox" value="grey" class="color-value">
      </div>
    </div>

  </div>


  <div class="col-sm-8 filter-option-output pattern-output">
    <div class="color-block">
      <div class="common-in-block pattern-box" data-my-class="pattern-box">
        <div class="color-backround color-black">&nbsp;</div>
        <p class="color-name">Part-2-child1</p>
        <input type="checkbox" value="black" class="color-value">
      </div>
      <div class="common-in-block pattern-box" data-my-class="pattern-box">
        <div class="color-backround color-blue">&nbsp;</div>
        <p class="color-name">Part-2-child2</p>
        <input type="checkbox" value="blue" class="color-value">
      </div>
      <div class="common-in-block pattern-box" data-my-class="pattern-box">
        <div class="color-backround color-red">&nbsp;</div>
        <p class="color-name">Part-2-child3</p>
        <input type="checkbox" value="brown" class="color-value">
      </div>
    </div>
  </div>

  <div class="col-sm-8 filter-option-output room-output">
    <div class="color-block">
      <div class="common-in-block room-box" data-my-class="room-box">
        <div class="color-backround color-black">&nbsp;</div>
        <p class="color-name">Part#3-child1</p>
        <input type="checkbox" value="black" class="color-value">
      </div>
      <div class="common-in-block room-box" data-my-class="room-box">
        <div class="color-backround color-blue">&nbsp;</div>
        <p class="color-name">Part#3-child2</p>
        <input type="checkbox" value="blue" class="color-value">
      </div>
      <div class="common-in-block room-box" data-my-class="room-box">
        <div class="color-backround color-red">&nbsp;</div>
        <p class="color-name">Part#3-child3</p>
        <input type="checkbox" value="brown" class="color-value">
      </div>
    </div>
  </div>

</div>

\$\endgroup\$
  • \$\begingroup\$ i will surely check this and reply back . \$\endgroup\$ – Manik May 4 '17 at 12:08
  • \$\begingroup\$ @Manik I've added live demo at the bottom of answer. You can check that. \$\endgroup\$ – Tushar May 4 '17 at 12:31
  • \$\begingroup\$ this is good solution friend \$\endgroup\$ – Manik May 4 '17 at 13:01
1
\$\begingroup\$

A mini review on this part of the code:

    if ($(this).hasClass("output-active")) {
      $(".filter-option-output").css("display", "none");
      $(this).removeClass("output-active");
    } else {
      $(".filter-option-output").css("display", "none");
      $(".color-output").toggle();
      $(this).addClass("output-active");
    }

This code basically calls $(".filter-option-output").css("display", "none"); in both cases, so you can extract it and put it up front.

Secondly, you are basically adding or removing "output-active" based on $(this).hasClass("output-active")), you can use the following for that: $( this ).toggleClass( "output-active" );

Finally, $() calls can be expensive, I would cache $(this) into $this.

Only the toggle statements remains then:

var $this = $(this),
    noOutputActiveClass = !$this.hasClass("output-active") ;

$(".filter-option-output").css("display", "none");
$this.toggleClass("output-active");
if( noOutputActiveClass ){
  $(".color-output").toggle();
}
\$\endgroup\$
  • \$\begingroup\$ $( this ).toggleClass( "output-active") is sufficient to toggle the class. \$\endgroup\$ – Tushar May 4 '17 at 11:40
  • \$\begingroup\$ Duh, you are absolutely right \$\endgroup\$ – konijn May 4 '17 at 12:07
  • \$\begingroup\$ thank you friends, i will surely check this and reply back \$\endgroup\$ – Manik May 4 '17 at 12:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.