0

I'm trying to use jQuery to modify an element that's "injected" externally. I've tried delegation with on but it didn't work.

Here's the page, scroll down and you'll see an avatar named "Sebastian" with <div class="Avatar">.

If I go right click, Console and type: $('.Avatar'), the element is identified, but this is only because I first clicked on "Inspect element" for that element. jQuery somehow "updated" the source and now it identifies the element.

Now, try to refresh the page and type $('.Avatar') again, jQuery will not identify the element (although it's already loaded on the page).

You can take a look under "A working example" how this script is injected into the page.

My question is, is it possible (and if so, how) to modify this HTML (which seems to be inserted dynamically as the page is loaded)? It doesn't seem to be using any sort of iFrame nor anything, it just dynamically loads into the page, yet jQuery is unable to recognize it (unless you "tell it" to do so by clicking on "Inspect element" on the actual element).

P.S. I've tried using on, delegate, it doesn't work.

anemaria20
  • 1,646
  • 2
  • 17
  • 36
  • I ran your page and I was able to access .Avatar after refreshing the page. What browser are you using? Maybe its a race condition? You might want to add a 'wait' routine to check for .Avatar before accessing it? Or perhaps a https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver to watch that area in the HTML? – Kummer Wolfe Feb 05 '19 at 13:08
  • As per their working example, talk.js exposes a promise, Talk.ready, which resolves when the script has loaded. It then creates the participants in the conversation. If you want to access the .Avatar element, you must do so after this step. Chain another .then at the end of the script, and you should be able to access the element within the scope of the function you pass to .then(). – Patrick Stephansen Feb 05 '19 at 13:10
  • @KummerWolfe I've tried it in Chrome/Opera, same result. It returns an object but with length 0. – anemaria20 Feb 05 '19 at 13:11
  • @PatrickStephansen tried it, didn't work. Chained another then() with: .then(function() { console.log($('.Avatar').length); }); And got 0 as a result. – anemaria20 Feb 05 '19 at 13:13
  • Possible duplicate of [Click event doesn't work on dynamically generated elements](https://stackoverflow.com/questions/6658752/click-event-doesnt-work-on-dynamically-generated-elements) – Majid Feb 05 '19 at 13:15
  • @Majid please remove the "possible duplicate" tag. I already said I've tried delegation and it didn't work. – anemaria20 Feb 05 '19 at 13:24
  • 2
    Looking again, on the demo page, the chat window is actually in an iframe, so the selector only finds the element when that iframe's document is in focus. The iframe has aria-label="TalkJS iframe" if you're having trouble spotting it. – Patrick Stephansen Feb 05 '19 at 13:32
  • @PatrickStephansen oh, wasn't aware of that, thanks. So basically, I added another "then" and then $("iframe").on("load", function() { var frame_body = $("iframe").contents(); console.log(frame_body); }); Thing is, frame_body length is 0 and I'm not sure why. – anemaria20 Feb 05 '19 at 13:50
  • I don't think you can inspect the contents of an iframe from a script if the iframe references a different domain. I get this error if I try: Uncaught DOMException: Blocked a frame with origin "https://talkjs.com" from accessing a cross-origin frame. – Patrick Stephansen Feb 05 '19 at 14:52
  • @PatrickStephansen so basically there's no way? – anemaria20 Feb 05 '19 at 15:31
  • You would have to create a situation where the parent site and iframe have the same origin. One way to do that is to create a proxy to the iframe address through a domain you control and reference that in the iframe href. At this point, it's probably better to check if talk.js exposes the functionality you want in another way. Manipulating iframe content from the parent window is very fragile even if both are hosted on the same domain. – Patrick Stephansen Feb 05 '19 at 15:52

1 Answers1

1

jQuery will not identify the element after page because it's in another iframe.

You said "It doesn't seem to be using any sort of iFrame nor anything", but in the end it's iframe.

The reason why you can find it when you go right click on element and then in developers tools you write $('.Avatar') is because once you inspect element (right click) inside developer tool iframe will change.

enter image description here

Furthermore, your parent iframe and iframe that have avatar element have same origin. Run document.domain inside parent and other iframe. Iframe with avatar have origin "app.talkjs.com" and parent iframe have origin"talkjs.com".

Subdomains may be same-origin. There’s a small exclusion in the “Same Origin” policy. If windows share the same second-level domain, for instance john.site.com, peter.site.com and site.com (so that their common second-level domain is site.com), they can be treated as coming from the “same origin”. https://javascript.info/cross-window-communication

You should be able to catch onload iframe event and then search for .avatar.

iframe.onload = function() {
    let newDoc = iframe.contentDocument;

    console.log(newDoc.getElementsByClassName("avatar");
};
Gardelin
  • 950
  • 11
  • 30