0

Consider:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
  <tbody>
    <tr>
      <td>Foo</td>
      <td>
        <p>
          <span><input type="checkbox" disabled="disabled" checked="checked">1 </span>
          <span><input type="checkbox" disabled="disabled"> 2</span>
          <span><input type="checkbox" disabled="disabled"> 3</span>
        </p>
      </td>
    </tr>
    <tr>
      <td>Bar</td>
      <td>
        <p>
          <span><input type="checkbox" disabled="disabled" checked="checked"> A</span>
          <input type="checkbox" disabled="disabled"> B
        </p>
      </td>
  </tbody>
</table>

Using jQuery, how do I only keep the <span> which has an input with the attribute checked? Basically, in the end, I only want the following HTML:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
  <tbody>
    <tr>
      <td>Foo</td>
      <td>
        <p>
          <span><input type="checkbox" disabled="disabled" checked="checked">1 </span>
        </p>
      </td>
    </tr>
    <tr>
      <td>Bar</td>
      <td>
        <p>
          <span><input type="checkbox" disabled="disabled" checked="checked"> A</span>
        </p>
      </td>
  </tbody>
</table>

Note, that for some reason, B for Bar intentionally isn't wrapped around <span> (I didn't write the HTML). Also, assume that the checked inputs will always be within <span>.

Lastly, I need a one-line jQuery command without (anonymous) functions, since the tool I'm using only supports one-liner jQuery statements. I eventually just want to extract the .text() of this HTML, hence I want to remove the text whose respective input isn't checked.

The closest I got was something like $("table").find("p:has(input)").contents().not("span:has(input:not(:checked))").remove().end().html() (doesn't work)

hobbes3
  • 28,078
  • 24
  • 87
  • 116

2 Answers2

0

One Line?? That's might be impossible

$(document).ready(function(){

  $("table tr td p").each(function(){
  
    var html = "";
    $(this).find('span').each(function(){
      if($(this).has('input[checked="checked"]').length){
        html += '<span>'+$(this).html()+'</span>';
      }
    });
    $(this).html(html);
    
  });

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
  <tbody>
    <tr>
      <td>Foo</td>
      <td>
        <p>
          <span><input type="checkbox" disabled="disabled" checked="checked">1 </span>
          <span><input type="checkbox" disabled="disabled"> 2</span>
          <span><input type="checkbox" disabled="disabled"> 3</span>
        </p>
      </td>
    </tr>
    <tr>
      <td>Bar</td>
      <td>
        <p>
          <span><input type="checkbox" disabled="disabled" checked="checked"> A</span>
          <input type="checkbox" disabled="disabled"> B
        </p>
      </td>
  </tbody>
</table>
Jawad Ahbab
  • 1,462
  • 1
  • 19
  • 31
  • 1
    Sorry, the source HTML doesn't have `` for `B`. This is intentional. That's why the logic has to be "empty all content of p EXCEPT for the span that has the checked input". – hobbes3 Jun 05 '19 at 21:38
  • But, I think he wants text nodes. In his samle (expectation) it has those. @Rory McCrossan – Jawad Ahbab Jun 05 '19 at 21:38
  • It works if you don't have a problem with **one Line** #hobbes3 – Jawad Ahbab Jun 05 '19 at 22:00
0

An updated answer to try and handle inputs that aren't wrapped in a <span>.

// Finds all checked input
var $targets = $('body').find('input:checked');

// Loop over each input
$($targets).each(function(){

    // If the parent isn't a span, then false
    var parent_span = ($(this).parent().is('span')) ? $(this).parent() : false;

    // If parent span is not false, empty the closest p and append the span, otherwise remove spans from parent p
    (parent_span !== false) ? $(this).closest('p').empty().append(parent_span) : $(this).closest('p').find('span').remove();

})

This will fall apart if you add another input that isn't wrapped in a <span> to the container though. I know you said that's how the HTML is but it would ideally be consistent.

Here's an update jsfiddle.

Jeramiah Harland
  • 854
  • 7
  • 15