Skip to Content

Take a look at this small gallery web app, do you think that it’s written entirely in UI5? The correct answer is “yes”, but with the help of Semantic UI and the UI5 JSX renderer.

This blog is meant to be a fast teaser for my presentation at Inside Track: Timisoara. We’ll take a glance over some useful JSX techniques for building custom controls that I’ve used throughout the development of the gallery app.

JSX Intro

JSX is a syntax extension for JavaScript popularised by ReactJS. The power of JSX comes from the fact that it can be mixed with regular JavaScript expressions. In order to work, it needs to be compiled (or “transpiled”) back into normal JavaScript using, for example, BabelJS.

The following ReactJS JSX snippet:

const element = (
    <h1 className="greeting">Hello, world!</h1>
);

Is compiled into the following JavaScript code:

const element = React.createElement(
    'h1', {className: 'greeting'}, 'Hello, world!'
);

For embedding expressions inside JSX, we just have to surround the JS expressions with curly brackets. This nesting of JavaScript and JSX can be done recursively to virtually any level.

JSX with UI5

A while back, I wrote a small BabelJS plugin for compiling JSX into UI5 render manager calls. It allows you to write something like this:

oRm.render(
	<div ui5ControlData={oC} class="title">
		<h1 class="ui center aligned header">
		{ oC.getTitle() }
		</h1>
		<div class="ui center aligned subtitle">
		{ oC.getSubtitle() }
		</div>
	</div>
);

And then compiles it into something along the lines of this:

	oRm.write("<div ");
	oRm.writeControlData(oC);
	oRm.addClass("title");
	oRm.writeClasses();
	oRm.write(">");
	oRm.write("<h1 ");
	oRm.addClass("ui");
	oRm.addClass("center");
	oRm.addClass("aligned");
	oRm.addClass("header");
	oRm.writeClasses();
	oRm.write(">");
	oRm.writeEscaped((oC.getTitle() || ""));
	oRm.write("</h1>");
	oRm.write("<div ");
	oRm.addClass("ui");
	oRm.addClass("center");
	oRm.addClass("aligned");
	oRm.addClass("subtitle");
	oRm.writeClasses();
	oRm.write(">");
	oRm.writeEscaped((oC.getSubtitle() || ""));
	oRm.write("</div>");
	oRm.write("</div>");

Notice that it is incredibly hard to understand what we are actually rendering when looking at the compiled code? Even if you would write it by hand and introduce some helper methods, it would be ugly to behold and difficult to grasp.

Techniques

So now that we have the very basic concept of what we can do with JSX, let’s look at some easy examples from the gallery app. In the following snippets, I will omit auto-generated IDs for brevity and consider that the oC variable contains the custom control. We will look at the JSX code and the rendered output at runtime.

Simple property substitution

One of the most basic of all JSX techniques: simply adding some “dynamic” text into some static HTML. Through “dynamic”, I mean taken from the custom control’s properties or from some variable in general.

Code Output
<div class="title">
	<h1 class="ui center aligned header">
	{ oC.getTitle() }
	</h1>
</div>
<div class="title">
	<h1 class="ui center aligned header">
		Title
	</h1>
</div>

(the control has a string property title with the value "Title")

Conditional rendering

This one is also fairly simple: it allows you to conditionally render a sub-tree of the DOM. It is based on the way in which the logical operators work in JavaScript with non-boolean values.

Code Output
<div class="ui container">
{
	!Device.system.phone &&
	<div class="right menu">
		<span>Menu</span>
	</div>
}
</div>



<!-- on phones: -->
<div class="ui container">
</div>

<!-- on everything else: -->
<div class="ui container">
	<div class="right menu">
		<span>Menu</span>
	</div>
</div>

Property enumeration

This can be easily used when you either have an array property or you obtain an array somehow (e.g. using a split) and you want to render a DOM subtree for each array element.

Code Output
<div class="extra images">
{
	(oC.getImages() || []).forEach(i => (
		<a><img src={ i }/></a>
	))
}
</div>
<div class="extra images">
	<a><img src="a.png"/></a>
	<a><img src="b.png"/></a>
	<a><img src="c.png"/></a>
</div>


(the control has a property string[] images with the value ["a.png", "b.png", "c.png"])

Child control enumeration

When you have multi-cardinality aggregations, you will inevitably want to render each child control in a loop:

Code Output
<div class="right menu grid">
{
	(oC.getRight() || []).forEach(i => {
		<div class="item">
			<ui5Control>{i}</ui5Control>
		</div>
	})
}
</div>


<div class="right menu grid">
	<div class="item">
		<!-- first child control DOM -->
	</div>
	<div class="item">
		<!-- second child control DOM -->
	</div>
	<div class="item">
		<!-- third child control DOM -->
	</div>
</div>

(the control has an aggregation right containing three child controls)

Dynamic CSS class name

This is fairly useful when you dynamically add a class based on the value of a property (or some other condition). This could be used to achieve an effect similar to the standard ToolbarDesign mechanism.

Code Output
<i class={["circular", oC.getIcon(),"icon"]}>
</i>






<!-- when icon = "globe" -->
<i class="circular globe icon"></i>

<!-- when icon = "user" -->
<i class="circular user icon"></i>

<!-- when icon = "money" -->
<i class="circular money icon"></i>

(the control has a string property icon)

Dynamic CSS class toggle

Whenever your control can be in two different states that differ by merely the presence of a CSS class, you can do the following:

Code Output
<a class={{
	link: true, item: true, 
	active: oC.getActive()
}}>
	Link
</a>



<!-- when active = true -->
<a class="link item active">
	Link
</a>

<!-- when active = false -->
<a class="link item">
	Link
</a>

(the control has a boolean property active)

Further examples

If you want to see more fleshed-out examples like the following control:

Then you can check out these two repositories on GitHub:

 

To report this post you need to login first.

Be the first to leave a comment

You must be Logged on to comment or reply to a post.

Leave a Reply