Display div value that matches with attribute from other div

Viewed 246

I have two divs created from PHP loop:

<div class="sku">
  <span class="sku-value" data-id="150">1000</span>
  <span class="sku-value" data-id="151">2000</span>
  <span class="sku-value" data-id="152">3000</span>
</div>

<div class="size-values">
  <span class="size-value" data-id="150">M</span>
  <span class="size-value" data-id="151">L</span>
  <span class="size-value" data-id="152">XL</span>
</div>

These divs has parent div called attributes.

sku-value and size-value have something in common: data-id attribute.

With CSS I'm manipulating the sku-value spans:

.sku-value {
  display:none;
} 

.sku-value.active {
   display:inline-block;
 }

With jQuery I'm displaying only the first size-value:

$('.sku-value:first').addClass('active');

So in this case when the page is loaded only this sku-value will be visible:

<span class="sku-value" data-id="150">1000</span>

With my code bellow I can successfully change the active class of each clicked size-value but how can I change the displayed sku-value that matches the data-id value?

For example: if a user click on one of size-value that has data-id 152, how can I display the sku-value that has data-id 152 and hide the current visible sku-value?

  $(document).ready(function(){
    $('.sku-value:first').addClass('active');

    $('.attributes').find('.size-value').on('click', function(){

      if ($this.hasClass('active')) {
        $this.removeClass('active');
      } else {
        $this.closest('.size-values').find('.size-value').removeClass('active');
        $this.addClass('active');
      }

    });
  });
2 Answers

To achieve what you require you can retrieve the data-id of the clicked element, then use filter() to retrieve all elements by that data attribute before setting the active class on them.

Here's an example showing how to do that, and also some tweaks to the logic to make it more succinct:

$(document).ready(function() {
  let $skuAttributes = $('.sku-value');
  let $sizeAttributes = $('.size-value');
  let $allAttributes = $skuAttributes.add($sizeAttributes);
  
  // set default state on page load
  $skuAttributes.first().addClass('active');
  $sizeAttributes.first().addClass('active');

  // on click of a size attribute, set active class on all relevant elements
  $sizeAttributes.on('click', function() {
    $sizeAttributes.removeClass('active');
    
    let dataId = $(this).data('id'); 
    $allAttributes.removeClass('active').filter((i, el) => el.dataset.id == dataId).addClass('active');
  });
});
div { font-size: 1.3em; }
.sku-value { display: none; }
.sku-value.active { display: inline-block; }
.active { color: #C00; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="attributes">
  <div class="sku">
    <span class="sku-value" data-id="150">1000</span>
    <span class="sku-value" data-id="151">2000</span>
    <span class="sku-value" data-id="152">3000</span>
  </div>

  <div class="size-values">
    <span class="size-value" data-id="150">M</span>
    <span class="size-value" data-id="151">L</span>
    <span class="size-value" data-id="152">XL</span>
  </div>
</div>

Here's a functional-style, vanilla-flavored solution I came up with. Several helper functions share the heavy lifting, so the main listener function stays simple and clean.

Instead of the active class, this uses a hidden class that can apply to sku spans as well as size spans.

(I'm late to the party because I wrote this script while I was offline today.)

const
  // Collects DOM elements as arrays
  sizes = [...document.getElementsByClassName("size-value")],
  skus  = [...document.getElementsByClassName("sku-value")],
  spans = [...sizes, ...skus],

  // Defines helper functions
  isHidden = (_this) => _this.classList.contains("hidden"),
  isActive = (_this) => sizes.every((size) => isHidden(size) || size === _this),
  showAll = (_these) => _these.forEach((_this) => _this.classList.remove("hidden")),
  hideAll = (_these) => _these.forEach((_this) => _this.classList.add("hidden")),
  filterByDataId = (_these, id) => _these.filter(_this => _this.dataset.id === id);

// Invokes listener when user clicks a size
sizes.forEach(size => size.addEventListener("click", hideAndShow));

// Defines listener
function hideAndShow({target}){ // Destructures click event
  if(isActive(target)){
    showAll(spans);
  }
  else{
    hideAll(spans);
    showAll(filterByDataId(spans, target.dataset.id));
  }
}
div { margin: 1em 0; }
span { padding: 0.1em 0.3em; border: 1px solid grey; }
.hidden{ display: none; }
<div class="sku">
    <span class="sku-value" data-id="150">1000</span>
    <span class="sku-value hidden" data-id="151">2000</span>
    <span class="sku-value hidden" data-id="152">3000</span>
  </div>
  <div class="size-values">
    <span class="size-value" data-id="150">Medium</span>
    <span class="size-value" data-id="151">Large</span>
    <span class="size-value" data-id="152">Xtra Large</span>
  </div>

Related