Search code examples
jqueryhyperlinkhrefchildrenattr

How to copy an a attribut value to an a sibling attribut using jQuery


I have a ul list elements where in each li elements there is a div with 2 children div's inside, i want it's second div > a element with the class of hover_icon_link to have the same href attr as the first div > a element has, my code works only on the first li element, the rest all take that same attr everywhere in every li, my code is as below jQuery:

$('li.product-category').each(function(){ 
    var attrLink = jQuery('div.post_featured > a').attr("href");
    $('div.post_thumb > a.hover_icon_link').attr("href", attrLink);
});

HTML:

    <ul class="products">
        <li class="product-category">
            <div class="post_item_wrap">
                <div class="post_featured">
                    <a href="#link1">Title here</a>
                </div>
                <div class="post_thumb">
                    <a href="#link2" class="hover_icon_link">title here</a>
                </div>
            </div>
        </li>
    </ul>

Solution

  • While you've already self-answered your question, which suggests you've worked out the problem for yourself, I thought I'd contribute another answer showing an alternative, along with explanations of both the original problem you were facing and the solution.

    First, then, the problem that you had was that in your code:

    // you select each <li> element with the class of '.product-category',
    // and use the each() method to iterate over that collection:
    $('li.product-category').each(function(){ 
    
        // here you select all elements that match the selector, meaning
        // you retrieve <a> every element on the page which is a child
        // of a <div class="post_featured"> element and retrieve the
        // 'href' attribute-value with the attr() method. When you use
        // a jQuery getter method on a collection the value returned is
        // the attribute-value of the first element in that collection
        // (of every element on the page that matches) not necessarily
        // the attribute-value of the intended <a>:
        var attrLink = jQuery('div.post_featured > a').attr("href");
    
        // here you select every <a class="hover_icon_link"> element in 
        // the document that is a child of a <div class="post_thumb">
        // element, and use the attr() method as a setter to update the
        // href attribute of every element in the document to the value
        // retrieved earlier:
        $('div.post_thumb > a.hover_icon_link').attr("href", attrLink);
    });
    

    // here we select all elements with the class of 'post_item_wrap'
    // and iterate over them using the each() method:
    $('.post_item_wrap').each(function() {
    
      // here we search within the current .post_item_wrap element,
      // represented by $(this), and within the current element we
      // use the find() method to find an <a> element which is a
      // descendant of an element with the class of 'post_featured',
      // and retrieve that href attribute-value:
      let href = $(this).find('.post_featured a').attr('href');
    
      // we again search within the current .post_item_wrap element
      // to find an <a> element which is a descendant of an element
      // with a class of 'post_thumb', and then update its href
      // attribute-value with the value find previously:
      $(this).find('.post_thumb a').attr('href', href);
    });
    *,
     ::before,
     ::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    ul,
    li {
      list-style-type: none;
    }
    
    li {
      border: 2px solid rebeccapurple;
      border-radius: 0.5em;
      overflow: hidden;
      margin: 0.5em auto;
    }
    
    div.post_featured {
      background-color: lightblue;
      margin: 0.3em 0;
    }
    
    div.post_thumb {
      background-color: palegreen;
    }
    
    a {
      display: flex;
      justify-content: space-around;
      align-content: center;
      width: 40vh;
    }
    
    a::after {
      display: content;
      content: '(' attr(href) ')';
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <ul class="products">
      <li class="product-category">
        <div class="post_item_wrap">
          <div class="post_featured">
            <a href="#link1">Title here</a>
          </div>
          <div class="post_thumb">
            <a href="#link2" class="hover_icon_link">title here</a>
          </div>
        </div>
      </li>
      <li class="product-category">
        <div class="post_item_wrap">
          <div class="post_featured">
            <a href="#link3">Title here</a>
          </div>
          <div class="post_thumb">
            <a href="#link4" class="hover_icon_link">title here</a>
          </div>
        </div>
      </li>
      <li class="product-category">
        <div class="post_item_wrap">
          <div class="post_featured">
            <a href="#link5">Title here</a>
          </div>
          <div class="post_thumb">
            <a href="#link6" class="hover_icon_link">title here</a>
          </div>
        </div>
      </li>
    </ul>

    JS Fiddle demo.

    Of course, this could be improved with destructuring, for example:

    // here we select all elements with the class of 'post_item_wrap',
    // and then iterate over each of those elements using the each()
    // method:
    $('.post_item_wrap').each(function(index, element) {
      // here we take advantage of the 'element', made available via jQuery's
      // anonymous function, and use Element.querySelectorAll() to retrieve both
      // <a> elements within the current .post_item_wrap element; we use
      // JavaScript's destructuring to assign those <a> elements to the variables
      // 'a' and 'b' (these are assigned in the order in which the <a> elements
      // are placed in the DOM):
      let [a, b] = element.querySelectorAll('a');
    
      // here we use Element.setAttribute() to update the attribute-value of the
      // 'href' attribute of the second <a> to be equal to the attribute-value
      // of the 'href' of the first <a> element:
      b.setAttribute('href', a.getAttribute('href'));
      // We could instead use:
      // b.href = a.href;
      // but that will use an absolute URL which may not be what you want:
    });
    *,
     ::before,
     ::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    ul,
    li {
      list-style-type: none;
    }
    
    li {
      border: 2px solid rebeccapurple;
      border-radius: 0.5em;
      overflow: hidden;
      margin: 0.5em auto;
      width: 15em;
    }
    
    div.post_featured {
      background-color: lightblue;
      margin: 0.3em 0;
    }
    
    div.post_thumb {
      background-color: palegreen;
    }
    
    a {
      display: flex;
      justify-content: space-around;
      align-content: center;
    }
    
    a::after {
      display: content;
      content: '(' attr(href) ')';
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <ul class="products">
      <li class="product-category">
        <div class="post_item_wrap">
          <div class="post_featured">
            <a href="#link1">Title here</a>
          </div>
          <div class="post_thumb">
            <a href="#link2" class="hover_icon_link">title here</a>
          </div>
        </div>
      </li>
      <li class="product-category">
        <div class="post_item_wrap">
          <div class="post_featured">
            <a href="#link3">Title here</a>
          </div>
          <div class="post_thumb">
            <a href="#link4" class="hover_icon_link">title here</a>
          </div>
        </div>
      </li>
      <li class="product-category">
        <div class="post_item_wrap">
          <div class="post_featured">
            <a href="#link5">Title here</a>
          </div>
          <div class="post_thumb">
            <a href="#link6" class="hover_icon_link">title here</a>
          </div>
        </div>
      </li>
    </ul>

    JS Fiddle demo.

    Of course, since it's also possible to iterate over a NodeList of element-nodes in plain JavaScript there's nothing stopping us from writing the previous approach in plain JavaScript, giving:

    // here we use document.querySelectorAll() to retrieve all elements in the
    // document that match the selector '.post_item_wrap', and then chain that
    // with NodeList.prototype.forEach() to iterate over that NodeList:
    document.querySelectorAll('.post_item_wrap').forEach(
      // using an Arrow function (since we have no need of 'this', and have
      // a reference to the current Node of the NodeList, which we pass into
      // the function:
      (element) => {
        // as above, we use Element.querySelectorAll() to retrieve all <a>
        // elements found within the current element-node, and use
        // destructuring to assign the first two of those <a> elements to
        // the variables 'a' and 'b':
        let [a, b] = element.querySelectorAll('a');
    
        // exactly as above:
        b.setAttribute('href', a.getAttribute('href'));
      });
    *,
     ::before,
     ::after {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    ul,
    li {
      list-style-type: none;
    }
    
    li {
      border: 2px solid rebeccapurple;
      border-radius: 0.5em;
      overflow: hidden;
      margin: 0.5em auto;
      width: 15em;
    }
    
    div.post_featured {
      background-color: lightblue;
      margin: 0.3em 0;
    }
    
    div.post_thumb {
      background-color: palegreen;
    }
    
    a {
      display: flex;
      justify-content: space-around;
      align-content: center;
    }
    
    a::after {
      display: content;
      content: '(' attr(href) ')';
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <ul class="products">
      <li class="product-category">
        <div class="post_item_wrap">
          <div class="post_featured">
            <a href="#link1">Title here</a>
          </div>
          <div class="post_thumb">
            <a href="#link2" class="hover_icon_link">title here</a>
          </div>
        </div>
      </li>
      <li class="product-category">
        <div class="post_item_wrap">
          <div class="post_featured">
            <a href="#link3">Title here</a>
          </div>
          <div class="post_thumb">
            <a href="#link4" class="hover_icon_link">title here</a>
          </div>
        </div>
      </li>
      <li class="product-category">
        <div class="post_item_wrap">
          <div class="post_featured">
            <a href="#link5">Title here</a>
          </div>
          <div class="post_thumb">
            <a href="#link6" class="hover_icon_link">title here</a>
          </div>
        </div>
      </li>
    </ul>

    JS Fiddle demo.

    References: