Browser & DOM

Elements provides special support for inter-operating with the most important platform API for Web Modules: the Browserobject, and the Document Object Model (DOM) that it provides access to.

The Browser

The static Browser class provided as part of Island RTL provides a few methods to access and create basic DOM objects:

  • GetWindowObject gives access to the global "Window" instance
  • GetElementById and GetElementByName allow look-up of existing HTML elements by ID and by name.
  • CreateElement and CreateTextNode create new DOM objects, for later insertion into the HTML.

Additional APIs are provided to perform Ajax and XmlHttp Requests (NewXMLHttpRequest), create WebSockets (NewWebSocket), and more. Please refer to the Browser Class reference of its source code on GitHub for a more complete overview of what is available.

Strong-Typing the DOM

By default, JavaScript objects present as opaque "Dynamic types that – like in JavaScript itself – allowing arbitrary calls that cannot be checked for validity until runtime.

Under the hood, these are instances of the EcmaScriptObject class provided by Island RTL, which encapsulates the dynamic nature of the object and handles dispatching calls by name, at runtime.

But Island RTL provides strongly-typed interfaces that let the compiler know what APIs should be available on a given object. This

  • lets the compiler enforce only valid calls are made, at compile time,
  • give you warnings for case mismatches and let you use mismatched case in the case-insensitive languages (Oxygene and Mercury),
  • gives you code completion and other IDE help while writing your code.

There are three ways to obtain a strongly-typed reference to a JavaScript object:

  1. Some APIs, such as Browser.GetWindowObject mentioned above, already return the proper well-known interface type, instead of dynamic, out of the box.
  2. Some APIs, such as GetElementById that cannot know the exact type will return a base type, e.g. Element. If known, these can be cast to the more concrete type that is expected (e.g. Button).
  3. Any JavaScript object, whether represented as Dynamic or a strongly-typed interface can simply be type-cast to a strongly-typed interface of your choice, as needed (but see Caveats, below).

Once a variable is strongly typed, the compiler can enforce access to only the known members.

// Window is strongly typed:
var lWidth := Browser.Window.innerWidth;

// Element can simply  be cast to a Form, if we know its type:
(Browser.GetElementByName('LoginForm') as HTMLFormElement).checkValidity();
// Window is strongly typed:
var lWidth = Browser.Window.innerWidth;

// Element can simply  be cast to a Form, if we know its type:
(Browser.GetElementByName("LoginForm") as HTMLFormElement).checkValidity();
// Window is strongly typed:
let lWidth = Browser.Window.innerWidth

// Element can simply  be cast to a Form, if we know its type:
(Browser.GetElementByName("LoginForm") as! HTMLFormElement).checkValidity()
// Window is strongly typed:
var lWidth = Browser.Window.innerWidth;

// Element can simply  be cast to a Form, if we know its type:
(Browser.GetElementByName("LoginForm") as HTMLFormElement).checkValidity();
' Window is strongly typed:
Dim lWidth = Browser.Window.innerWidth;

' Element can simply  be cast to a Form, if we know its type:
CType(Browser.GetElementByName("LoginForm"), HTMLFormElement).checkValidity()

Caveats

Keep in mind that the strongly-typed interfaces are merely fronts for the compiler to know what members are expected to exist on the underlying JavaScript object. In reality, your WebAssembly code is still interacting with a EcmaScriptObject instance that represents the JavaScript object and will dispatch calls dynamically as needed, at runtime.

That means calls can still fail at runtime, for example if

  • the JavaScript object for some reason does not implement the expected member,
  • the dynamic interface declaration seen by the compiler was wrong,
  • you cast a JavaScript object to the wrong interface.

See Also