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.

Weblab concept: a one to one mapping of components in Matlab and JS

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 the Component class. In fact, a Frame 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 a Frame, Components may have Component children. For that to happen, components inherit from the Container 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 also Containers.
  • 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 and HasCallbackProperty: how we can define our own property attributes to add neat behaviour to our classes (check the constructor of the Component class).
  • How Weblab handles fetching data from the view given the asynchronous nature of the uihtml update method (check the Promise class, and the Component 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).

Categorized in: