How to target Elements in a HTML Widget


(Mark Hunte) #1

You often need to access and use an element you have placed in the innerHTML of an HTML Widget

for example, a video element.

<video width="100%" id="myVideo" preload="auto" x-webkit-airplay="true" webkit-playsinline="true">
    <source src="${resourcesFolderName}/Untitled.mp4" type="video/mp4">
    
</video>

It may seem like you should just be able to use the normal hypeDocument Syntax to get the video element,

var myVid= hypeDocument.getElementById('myVideo');

or indeed the documents syntax,

var myVid= document.getElementById('myVideo');

But you will quickly find that this does not work as expected. You will either get an undefined returned and most likely an error on you next line.

Why…?

A HTML Widget is in effect an iFrame. Which is itself a completely separate web page from it’s parent.
The parent being your main web page.

As shown here.

This being the case the Parent does not have the same window,document or body context as the iFrame. It will NOT be able to access directly anything within the iFrame.

The HTML Inline Frame Element:

represents a nested browsing context, effectively embedding another HTML page into the current page.
In HTML 4.01, a document may contain a head and a body or a head and a frame-set, but not both a body and a frame-set. However, an iframe can be used within a normal document body. Each browsing context has its own session history and active document. The browsing context that contains the embedded content is called the parent browsing context. The top-level browsing context (which has no parent) is typically the browser window.


So how can we access stuff in the ** HTML Widget**.

The simplest way is to get the first child Element/Node of the widget. This will be the iFrame.

var iframe= hypeDocument.getElementById('theWidget').children[0];

Node.children is a read-only property that returns a live HTMLCollection of the child elements of Node.

Once we have the iframe as an object, we can then drill down into it.
First we need to get it’s Document content object.

var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;

We return contentDocument or contentWindow.document depending on browser compatibility

And now that we have the document object we can finally get the element we are after.

var myVid =  iframeDocument.getElementById('myVideo')

If using an HTML Widget is not essential, then it would be simpler to use a Rectangle shape and edit it’s innerHtml.

The Rectangle can take the same video element code as above.

We do not even need to first get the Rectangle as an object first. Because it is in the same context as it’s parent node and does not correspond to a web page in itself. It is just a Div with content.

So to get the video element. We can access it directly by it’s id with one line of code.

var myVid= hypeDocument.getElementById('myVideo') 

Widget project:
WidgetVideoElement.hype.zip (2.7 MB)

Rectangle project
RectVideoElement copy.hype.zip (2.7 MB)



Access child HTML widget/iframe content from Hype doc parent?
Change inline element style onclick
Tips and Tricks of the Month
Change inline element style onclick
Set element property inside innerHTML box
Dynamic variable to function
Hide fullscreen button in video control
(Greg) #2

This is a great tip of the month candidate.


(Mark Hunte) #3

Cheers Greg, I found a lot of people seemed to be trying to do this.


(Jean-Guy Boulay) #4

Really Great Info. Thank you! I remember reading something in documentation about the rectangles inside symbols must be referenced in a special way as well. I can’t find that information anymore. I think it’s something like:
var myVid= hypeDocument.symbolInstance.element(.).getElementById('myVideo')

Can anyone enlighten me?


(Jonathan Deutsch) #5

The fundamental issue with items in symbols is that if you have multiple instances of that symbol, then the id becomes meaningless as you have two elements with the same id. So instead of using an id for an element in a symbol, you should use a class. You can use standard getElementsByClassName() function. If you know which symbol you want to look into (which can have its own ID), then your code would look something like:

var videos = hypeDocument.getSymbolInstanceById("mySymbolID").getElementsByClassName("myVideoClassName");
var myVideo = videos[0]; // unsafe, make sure there really is video here