It’s been a long time since I post. But in reality I haven’t stopped working with uihtml elements. Back in April I participated in the first “Lighting Talks” organized by the Mathworks team on Reddit, and I showcased some of the nice things that we can display in our apps with the HTML element. And right before summer I published on GitHub and FEX what I called Weblab, a fully fledged framework to develop web-based components.
Today I want to continue on where I left it in last post (creating an abstract component) by diving a bit into Weblab. If you remember that post, we managed to create a Component
class that wrapped around a uihtml element and that was able to handle the dispatching of data between Matlab and JavaScript.
Frames and components, the core of Weblab
Unfortunately, the design of our previous Component
implied that one component required one HTML document. And that was not ideal. Weblab is envisioned differently… its premise is that a component class in Matlab should not be linked to an HTML file, but to a JavaScript class. When the Matlab component object is created, the JS mapped to it is dynamically inserted into the HTML.
Frame
The Frame
is our wrapper for the uihtml elements, and it is responsible for the actual communication between Matlab and JS (controlling the Data
property of the uihtml, essentially). It also knows all the components that are inside of it.
When a graphics update
happens (drawnow
), the Frame is responsible for sending its events to its counterpart (yes! we have a Frame in Matlab and a Frame in JS). The counterpart is then in charge of finding the component that the event refers to, and then dispatching the event to that component.
A Frame in Matlab looks like the code below (it’s very simplified, check the source code if you want to see all the intricacies!). Note how the Frame stores an array of “EventsToPublish” that are sent to the view when the update
method is called
classdef Frame < matlab.ui.componentcontainer.ComponentContainer
properties (SetAccess = private)
Children Component % list of components inside the frame
EventsToPublish Event % events in queue and ready to be sent to the view
HTMLElement % uihtml
end
methods
function publish(this, event)
this.EventsToPublish(end + 1) = event; % append to the queue
end
end
methods (Access = protected)
function setup(this)
this.HTMLElement = uihtml(.., "DataChangedFcn", @(~,~) this.dispatchEvent());
end
function update(this)
this.HTML.Data = this.EventsToPublish; % send to view
this.EventsToPublish = [];
end
end
methods (Access = private)
function dispatchEvent(this)
event = this.HTMLElement.Data; % get the event from the uihtml Data
idx = [this.Children.ID] == event.id; % find the children the event refers to
this.Children(idx).handleSubscription(event); % dispatch to component
end
end
end
Component
A Component
is simply an element that can communicate to its counterpart by publishing events or subscribing to them. To establish a link between a Matlab and the JS component, they have to share a unique identifier.
Components also have a reference of the Frame they live on. When they publish an event, they are actually passing it onto the Frame, which will then pass it to the component counterpart.
This is in essence how a component looks in Matlab:
classdef Component < handle
properties (SetAccess = private)
ID string % unique identifier
Subscriptions containers.Map % events and callbacks
Frame Frame % parent Frame
end
methods
function publish(this, event)
event.ID = this.ID; % the event needs the ID of the component
this.Frame.publish(event); % send to the Frame
end
function subscribe(this, eventName, callback)
this.Subscriptions(eventName) = callback; % store subscription
end
end
methods (Access = ?Frame)
function handleSubscription(this, event)
feval(this.Subscriptions(event.Name), event.Data); % evaluate subs. callback
end
end
end
An image explains everything better
Containers and other details
This was a very simplified take on the Frame
and Component
classes. In reality, there are a ton of details that complicate how Weblab works. I am going to list a few, so that if you decide to check the source code, you know what you are looking at:
Frames
inherit from theComponent
class. In fact, aFrame
is a wrapper for the <body> of the HTML document, which can also subscribe or publish events.- The framework is implemented as a composite pattern. Instead of nesting all the
Components
inside aFrame
,Components
may haveComponent
children. For that to happen, components inherit from theContainer
class. Containers are then a special type of component that hold a reference of their children and that can publish events to dynamically insert a child into the view. As you may have guessed,Frames
are alsoContainers
. - Besides publishing and subscribing, Matlab components can
fetch
data from JS. In other words, they can ask for information from their JS counterpart. In fact, fetching is just a combination of publishing and a subscribing to whatever the JS component replies back.
In the next posts
I encourage you to read the source code of Weblab, particularly the Matlab side. We haven’t looked deeply into the JS one, but mainly because there are many JS specific things that I am assuming that the average Matlab programmer doesn’t know about (bundlers, dynamic imports, Svelte, CSS in JS, …). But don’t worry, we will get there!
The next posts are going to still focus on the Matlab side of Weblab. I leave you know with the topics I have in mind, and links so that you can dive into the code before the posts are published
- Special property attributes,
CanBeStained
andHasCallbackProperty
: how we can define our own property attributes to add neat behaviour to our classes (check the constructor of theComponent
class). - How Weblab handles fetching data from the view given the asynchronous nature of the uihtml update method (check the
Promise
class, and theComponent
fetch method) - How fully-fledge styling from Matlab is managed in Weblab thanks to CSS in JS libraries (you can start checking the
Styled
mixin class).