Home > Back-end >  Javascript - Automate duplicating tags from parent div to child div based on class snippet
Javascript - Automate duplicating tags from parent div to child div based on class snippet

Time:07-25

I would like to automate duplicating a class from a parent div to each separate child span based on a word.

As an example: parent div contains the following classes: grid-item tag-street-style tag-slender tag-classic tag-navy tag-grey tag-white is-loaded

I would like to duplicate any classes within the parent div with the precursor "tag-" and place them into each separate child span. In this case, the parent div contains the classes with the initial "tag-" word: tag-street-style tag-slender tag-classic tag-navy tag-grey tag-white

Some other parent divs will contain other classes that contain the initial word "tag-"

The "tag-" classes can be different in other parent divs but there will always be 5 "tag-" classes. As an example, a different parent div may contain the following classes with the initial "tag-" word: tag-smart-style tag-casual tag-modern tag-red tag-black tag-green

I already have a code snippet but this is locked in to 5 specific "tag-" classes. Here is the code:

let classMap = {
    "tag-street-style": ".colour-tag-1",
    "tag-slender": ".colour-tag-2",
    "tag-navy": ".colour-tag-3",
    "tag-grey": ".colour-tag-4",
    "tag-white": ".colour-tag-5",
  };

I would like the first "tag-" class identified within the parent div to be duplicated into "colour-tag-1" within the first child span.

Then I would like the second "tag-" class identified within the parent div to be duplicated into "colour-tag-2" within the second child span.

Then I would like the third "tag-" class identified within the parent div to be duplicated into "colour-tag-3" within the third child span.

Then I would like the fourth "tag-" class identified within the parent div to be duplicated into "colour-tag-4" within the fourth child span.

Then I would like the fifth "tag-" class identified within the parent div to be duplicated into "colour-tag-5" within the fifth child span.

$(document).ready( function() { 
  $(".grid-item .grid-meta-wrapper").each(function(e){
    $(this).append('<div ><span >tag1</span><span >tag2</span><span >tag3</span><span >tag4</span><span >tag5</span></div>');
  });
  let classMap = {
    "tag-street-style": ".colour-tag-1",
    "tag-slender": ".colour-tag-2",
    "tag-navy": ".colour-tag-3",
    "tag-grey": ".colour-tag-4",
    "tag-white": ".colour-tag-5",
  };
  for (let cls in classMap) {
      document.querySelector(classMap[cls]).classList.add(cls);
  }
});
<style>
.tag-street-style {
    background-color: purple;
}

.tag-slender {
    background-color: red;
}

.tag-navy {
    background-color: blue;
}

.tag-grey {
    background-color: grey;
}

.tag-white {
    background-color: black;
    color: white;
}

.tag-red {
    background-color: black;
    color: red;
}

.tag-black {
    background-color: white;
    color: black;
}

.tag-green {
    background-color: black;
    color: green;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div >
  <section >
    <div >
      <div > T-Shirt </div>
      <div >
        <div >
          <span>12.99</span>
        </div>
      </div>
    </div>
    <div ></div>
  </section>
</div>
<br><br><br>
<div >
  <section >
    <div >
      <div > T-Shirt </div>
      <div >
        <div >
          <span>12.99</span>
        </div>
      </div>
    </div>
    <div ></div>
  </section>
</div>

CodePudding user response:

First, here is a testable solution:

$(document).ready( function() { 
  $(".grid-item .grid-meta-wrapper").each(function(e){
    $(this).append('<div ><span >tag1</span><span >tag2</span><span >tag3</span><span >tag4</span><span >tag5</span></div>');
  });
  let classes = [...document.getElementById("tag-specifier").classList].filter(item => item.indexOf("tag-") === 0);
  for (let index = 0; index < classes.length; index  ) {
      let currentItem = document.querySelector(".colour-tag-"   (index   1));
      if (currentItem !== null) {
          currentItem.classList.add(classes[index]);
      }
  }
});
.tag-street-style {
    background-color: purple;
}

.tag-slender {
    background-color: red;
}

.tag-navy {
    background-color: blue;
}

.tag-grey {
    background-color: grey;
}

.tag-white {
    background-color: black;
    color: white;
}

.tag-red {
    background-color: black;
    color: red;
}

.tag-black {
    background-color: white;
    color: black;
}

.tag-green {
    background-color: black;
    color: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="tag-specifier" >
  <section >
    <div >
      <div > T-Shirt </div>
      <div >
        <div >
          <span>12.99</span>
        </div>
      </div>
    </div>
    <div ></div>
  </section>
</div>

Now, let's understand it:

  • I have added the id of tag-specifier to the element which has the classes, so the code will have an easy time finding the classes to work with
  • document.getElementById("tag-specifier").classList is returning an object of key-value pairs where the keys are indexes (starting from 0) and the values are class names
  • I convert the result of classList into an array via [...document.getElementById("tag-specifier").classList] because I intend to use the filter() function of the array, alternatively I could have written a loop with similar effect
  • .filter() is being called for the newly converted array. This function takes a callback (more on that below) that determines which items we are interested about from the array and returns an array that contains only the items that the callback found interesting
  • a callback is a function that is scheduled to be executed at some future point of time
  • in our case, the callback of .filter() is a function which will be executed for each elements of the array and will evaluate them whether they are interesting
  • our callback is item => item.indexOf("tag-") === 0, which is a function (we use the arrow operator => to differentiate the parameter, which is item and the actual function body, which is item.indexOf("tag-") === 0), that is, we are only interested about items whose name starts with tag-
  • after the call for .filter(), the value assigned to classes is an array of class names that only holds valuable class names from our perspective, that is, class names starting with tag-
  • we loop classes using a variable we create for this purpose, named index
  • we search for the element that corresponds to the selector of ".colour-tag-" (index 1). The reason for the index 1 is that Javascript arrays are 0-indexed and your tag indexes start from 1
  • note that (index 1) is enclosed into parantheses. The reason for this is that is an operator that acts both as concatenator and numeric addition and evaluates from left-to-right, that is, without the paranthesis around (index 1) the result of ".colour-tag-" index 1 would be looking like .colour-tag-01 instead of .colour-tag-2
  • we check whether currentItem exists, so we program defensively, so, if any anomaly occurs, we intend our code to handle it gracefully
  • if currentItem existed, then we add the current class, which is classes[index]

EDIT

The initial solution I have implemented was assuming that we deal with a single such case, while your problem included multiple similar cases on the same page. To solve this issue, I have added an extra layer to the solution, querying the roots of all relevant subtrees in HTML and using them as the context of their respective problem-spaces.

Here is a snippet that illustrates it (yes, the first 3 tags will be unstyled, but this is not due to the logic of the code, but it is rather due to the styling specification of the structure):

$(document).ready( function() { 
  $(".grid-item .grid-meta-wrapper").each(function(e){
    $(this).append('<div ><span >tag1</span><span >tag2</span><span >tag3</span><span >tag4</span><span >tag5</span><span >tag6</span></div>');
  });
  
  for (let context of $(".list-grid .grid-item")) {
    let idDeclaration = context.id;
  
    let classes = [...context.classList].filter(item => item.indexOf("tag-") === 0);
    for (let index = 0; index < classes.length; index  ) {
        let currentItem = context.querySelector(".colour-tag-"   (index   1));
        if (currentItem !== null) {
            currentItem.classList.add(classes[index]);
        }
    }
  }
});
.product-view-item-colour-tags .tag-navy {
    background-color: blue;
}

.product-view-item-colour-tags .tag-grey {
    background-color: grey;
}

.product-view-item-colour-tags .tag-white {
    background-color: black;
    color: white;
}

.product-view-item-colour-tags .tag-red {
    color: red;
}

.product-view-item-colour-tags .tag-black {
    background-color: white;
    color: black;
}

.product-view-item-colour-tags .tag-green {
    color: green;
}

.product-view-item-colour-tags .tag-yellow {
    background-color: black;
    color: yellow;
}

.product-view-item-colour-tags .tag-orange {
    color: orange;
}

.product-view-item-colour-tags .tag-pink {
    color: pink;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div >

<div id="thumb-product-3-9" >
  <section >
    <div >
      <div > T-Shirt 1</div>
      <div >
        <div >
          <span>9.99</span>
        </div>
      </div>
    </div>
    <div ></div>
  </section>
</div>
<br>
<div id="thumb-product-3-12" >
  <section >
    <div >
      <div > T-Shirt 2</div>
      <div >
        <div >
          <span>12.99</span>
        </div>
      </div>
    </div>
    <div ></div>
  </section>
</div>
<br>
<div id="thumb-product-3-1" >
  <section >
    <div >
      <div > T-Shirt 3</div>
      <div >
        <div >
          <span>14.99</span>
        </div>
      </div>
    </div>
    <div ></div>
  </section>
</div>
<br>
<div id="thumb-product-3-4" >
  <section >
    <div >
      <div > T-Shirt 4</div>
      <div >
        <div >
          <span>15.99</span>
        </div>
      </div>
    </div>
    <div ></div>
  </section>
</div>

</div>

  • Related