2
$('body').append($('#add-done-modal, #add-failed-modal', data));

This code should append the div with id add-done-modal and add-failed-modal to body. Those div are served in data among other stuff. I'm sure the html in data is perfectly fine and intended. The code never find the id. I'm using jQuery 3.3.1. I know classes are a solution, but would be rather unwieldy due to various modal that could be or not chosen depending on the client calling.

EDIT: A simple $('#add-done-modal', data) returns an empty jQuery object. I am, once again, sure #add-done-modal is in data.

EDIT: This function is called by a clickevent:

function popup(url, name) {
  $.get(url, (data) => {
    $('#loading-modal .modal-body').html($('#product', data));
    // Can't find '#add-done-modal' nor '#add-failed-modal'
    let x = $('#add-done-modal', data);
    x = $('#add-failed-modal', data);
    $('body').append($('#add-done-modal, #add-failed-modal', data));
    // Initialize jQuery-UI or Bootstrap stuff loaded above here. Working.
  });

  $('#loading-modal .modal-header .modal-title').html(name);
  $('#loading-modal').modal('show');
}

Here is the content returned by the AJAX call:

<!DOCTYPE html>
<html lang="fr">
  <head>
    <!-- Head stuff -->
  </head>
  <body>
    <div id="all">
      <div class="top-bar">
        <div class="container">
          <div class="row d-flex align-items-center">
            <div class="col-8 col-lg-9">
              <form action="/updatelocale/" method="POST">
                <select class="bs-select" onchange="this.form.submit();">
                  <!-- Locale options, can be disregarded -->
                </select>
              </form>
            </div>
            <div class="col justify-content-md-end">
              <div class="row">
                <!-- Login and some buttons, not used -->
              </div>
            </div>
          </div>
        </div>
      </div>
      <header class="nav-holder make-sticky">
        <div id="navbar" role="navigation" class="navbar navbar-expand-lg">
          <!-- A pretty navbar -->
        </div>
      </header>
      <div id="heading-breadcrumbs">
        <!-- Cute breadcrumbs -->
      </div>
      <div id="content">
        <!-- Product, loading this from data works -->
        <div id="product" class="container">
          <div id="productMain" class="row">
            <!-- Stuff inside #product -->
          </div>
        </div>
      </div>
      <footer class="main-footer">
        <!-- Pretty footer -->
      </footer>
    </div>
    <!-- Modal #add-done-modal -->
    <div id="add-done-modal" tabindex="-1" role="dialog" aria-labelledby="add-done-modalLabel" aria-hidden="true" class="modal fade">
      <div role="document" class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h4 id="add-done-modalLabel" class="modal-title">cart.add.done</h4>
            <button type="button" data-dismiss="modal" aria-label="Close" class="close"><span aria-hidden="true">×</span></button>
          </div>
          <div class="modal-body">cart.add.done.long</div>
          <div class="modal-footer"><button data-dismiss="modal" class="btn">modal.close</button></div>
        </div>
      </div>
    </div>
    <!-- Modal #add-failed-modal -->
    <div id="add-failed-modal" tabindex="-1" role="dialog" aria-labelledby="add-failed-modalLabel" aria-hidden="true" class="modal fade">
      <div role="document" class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h4 id="add-failed-modalLabel" class="modal-title">cart.add.failed</h4>
            <button type="button" data-dismiss="modal" aria-label="Close" class="close"><span aria-hidden="true">×</span></button>
          </div>
          <div class="modal-body">cart.add.failed.long</div>
          <div class="modal-footer"><button data-dismiss="modal" class="btn">modal.close</button></div>
        </div>
      </div>
    </div>
    <div id="login-modal" tabindex="-1" role="dialog" aria-labelledby="login-modalLabel" aria-hidden="true" class="modal fade">
      <div role="document" class="modal-dialog">
        <!-- I don't care about this modal -->
      </div>
    </div>
  </body>
</html>

EDIT: Here is a fiddle with some tests. After rendering the document to the DOM, $('#add-done-modal, #add-failed-modal') and $('#add-done-modal') find the modals, before it doesn't. In this second fiddle with static HTML, I checked if the modals were found, they were.

Is there any limit to jQuery context length for HTML strings?

10
  • What debugging have you done? Have you checked the result of $('#add-done-modal, #add-failed-modal', data)? Commented Mar 7, 2018 at 1:38
  • 1
    Do note that data has to be an Element or a jQuery object... api.jquery.com/jQuery/#jQuery-selector-context Commented Mar 7, 2018 at 1:38
  • @Phil Yes I did. "The code never find the id." $('#add-done-modal, #add-failed-modal') never find anything but the div are in data. Commented Mar 7, 2018 at 2:37
  • 1
    @MikeMcCaughan No, it doesn't. It can also be an html string not in the document. Commented Mar 7, 2018 at 2:39
  • @AlexandreParent where exactly does it say it can be an HTML string? The documentation clearly states "A DOM Element, Document, or jQuery to use as context" Perhaps you should try let context = $(data) and use that Commented Mar 7, 2018 at 2:46

1 Answer 1

1

If you want to work with the HTML string properly, I'd suggest parsing it into a document, eg

const domParser = new DOMParser()
const doc = domParser.parseFromString(data, 'text/html')

then use doc in your jQuery selectors, eg

$('#add-done-modal', doc)

When jQuery encounters a context, it simply converts the expression to...

jQuery(context).find(selector)

See https://github.com/jquery/jquery/blob/3.3.1/src/core/init.js#L99

The issue here is that jQuery parses entire documents into a jQuery object containing the top-level elements under <body>. See http://api.jquery.com/jQuery/#jQuery2

But if the string appears to be an HTML snippet, jQuery attempts to create new DOM elements as described by the HTML

For example, taking your HTML as a string...

$(html)

gives me a jQuery object with 15 elements, mostly empty text and some comment nodes but including

#3  <div id="all">...</div>
#7  <div id="add-done-modal"...>...</div>
#11 <div id="add-failed-modal"...>...</div>
#13 <div id="login-modal"...>...</div>

Using this object as a selector context, you can find elements that are children of those 5 but not those elements themselves. This is why you can find #product for example.

Sign up to request clarification or add additional context in comments.

7 Comments

I didn't know you could create in-memory document... Considering jQuery finds the selectors once the HTML is parsed, it may well be the solution.
@AlexandreParent yeah, I had a feeling it wouldn't. It seems odd though.
Second solution works! May I suggest you remove first solution? And your guess is false because it does works for elements much higher in the string.
Nah, I'll leave it. Like I said, it should work :)
@AlexandreParent Sometimes it uses it to parse / format the data passed to the success callback (eg 'json'). For 'html' though (and I've only just read this in the doco), the result is an HTML string. Why jQuery is unable to use that string as a context, I'm not sure but $(data) doesn't result in anything useful either which was the basis for my "guess" above
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.