2

I have following code in my web page. I need to find the product name that appears after a span with class of pn. When I run the code below, I get empty string from getFirstProduct method and also an empty string from getSecondProduct method. However, if I use following expression then I get the correct product name: $("#p0 span.pn")[0].nextSibling.data or $("#p1 span.pn")[0].nextSibling.data but this is using JavaScript and I was wondering if there is a pure jquery solution.

A demo for this question is at this URL: demo code

Question : What should be the correct selector in these two methods so they return Product 0 and Product 1 respectively?

Code to find product name

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id='p0'>
     <div>some content</div>
     <div></div>
     <div><span class='t pn'>Product : </span>Product 0</div>
     <div></div>
     <div>some content</div>
     <div>some content</div>
    </div>
    <div id='p1'>
     <div>some content</div>
     <div></div>
     <div><span class='t pn'>Product : </span>Product 1</div>
     <div></div>
     <div>some content</div>
     <div>some content</div>
</div>
<button type="button" onclick="var x =  getFirstProduct(); alert(x);">Get First Product</button>
<button type="button" onclick="var x =  getSecondProduct(); alert(x);">Get Second Product</button>

<script>
function getFirstProduct() {
    return $("#p0  span.pn").next().text();
}

function getSecondProduct() {
   return $("#p1  span.pn").next().text();
}
</script>

UPDATE 1

Based on answer given and also the post whose duplicate this was marked as, I came up with following code that works perfectly. Demo code for solution is at this URL: solution code demo.

The idea is to get the parent div of span with class of pn and then get all types of nodes only under it i.e. one level down from parent only, which is done by contents() method ( and not children() method since children will ignore text nodes). This would give us two elements - span and the text following the span element since these two are the only immediate children of parent div. The text node would be the name of Product that we are seeking.

When seeking text nodes in jquery, it seems that contents() method will almost always be required.

Code that works

<div id='p0'>
     <div>some content</div>
     <div></div>
     <div><span class='t pn'>Product : </span>Product 0</div>
     <div></div>
     <div>some content</div>
     <div>some content</div>
    </div>
    <div id='p1'>
     <div>some content</div>
     <div></div>
     <div><span class='t pn'>Product : </span>Product 1</div>
     <div></div>
     <div>some content</div>
     <div>some content</div>
</div>
<button type="button" onclick="var x =  getFirstProduct(); alert(x);">Get First Product</button>
<button type="button" onclick="var x =  getSecondProduct(); alert(x);">Get Second Product</button>

<script>
function getFirstProduct() {
 return $("#p0  span.pn").parent().contents().filter(function(index) { return this.nodeType === 3 ;}).text();
}

function getSecondProduct() {
   return $("#p1  span.pn").parent().contents().filter(function(index) { return this.nodeType === 3 ;}).text();
}
</script>
Community
  • 1
  • 1
Sunil
  • 20,653
  • 28
  • 112
  • 197
  • @j08691, That was a good pointer, though not easy and quick to grasp. But with some effort it's all clear now. I learnt two very important jquery concepts - `contents` and `filter`. – Sunil Dec 27 '15 at 00:06

1 Answers1

1

$(function() {
  
  $('#out0').on('click', function(e) {

    
    getFirstProduct();
  });


  $('#out1').click(function(e) {

    
    getSecondProduct();
  });

  function getFirstProduct() {
    $("#p0 span.pn").text('');
    var txt0 = $("#p0 span.pn").parent().text();
    $('#out0').text(txt0);
  }

  function getSecondProduct() {
    $('#p1 span.pn').text('');
    var txt1 = $("#p1 span.pn").parent().text();
    $('#out1').text(txt1);
  }

});
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id='p0'>
  <div>some content</div>
  <div></div>
  <div><span class='t pn'>Product : </span>Product 0</div>
  <div></div>
  <div>some content</div>
  <div>some content</div>
</div>
<div id='p1'>
  <div>some content</div>
  <div></div>
  <div><span class='t pn'>Product : </span>Product 1</div>
  <div></div>
  <div>some content</div>
  <div>some content</div>
</div>
<button id="out0">Get First Product</button>
<button id="out1">Get Second Product</button>
zer00ne
  • 41,936
  • 6
  • 41
  • 68
  • Great. That works and I tried in Edge, IE11, Chrome and FireFox. Why is `next` not working out in my case? – Sunil Dec 26 '15 at 23:32
  • The span is inside the div that has your text. So that div is actually the span's parent. So from the span you would use `.parent().next().text()` I believe. That's great that it works for you. :) – zer00ne Dec 26 '15 at 23:40
  • The only issue with the code you gave is that it's also getting `Product :` as part of product name. I only wanted `Product 0` or `Product 1` and not `Product : Product 0` or `Product : Product 1`. – Sunil Dec 26 '15 at 23:45
  • The `Product:` text belongs to the span... I don't think that'll be a prob, wait one sec for update. – zer00ne Dec 27 '15 at 00:00
  • @Sunil, ok it's updated and ready for review, sir. I'll be around if you need anymore help. – zer00ne Dec 27 '15 at 00:16
  • It's still prefixing the product name with `Product :`. – Sunil Dec 27 '15 at 00:20
  • My bad, I thought you wanted that included because the original result was sans `product:` prefix. I think Chrome and IE Edge render differently. – zer00ne Dec 27 '15 at 00:22
  • No, the original code was giving the `Product: ` prefix. – Sunil Dec 27 '15 at 00:24
  • Your right, I think my expectations mentally blinded me. I'll be back with update. – zer00ne Dec 27 '15 at 01:00
  • @Sunil, that was harder than I thought. That's one reason I prefer JS, string methods are powerful yet simple. I learned that jQuery *flattens* arrays when rendering strings eventListeners are removed. – zer00ne Dec 27 '15 at 03:44
  • No problems. I think your approach is to remove the span text and the get parent text. I think `$("#p0 span.pn)[0].nextSibling.data` would give the first product name in a short and quick manner. May be its best to combine jquery and JavaScript, rather than do it in pure jquery. – Sunil Dec 27 '15 at 05:00
  • Indeed, I have a habit to think in JS, the conveniences of jQuery eludes me at times. I'm glad you came up with a succinct solution. :) – zer00ne Dec 28 '15 at 02:11