“Modularization is the activity of dividing a product or system into interchangeable modules.” (stolen somewhere)
As long as things stay simple and you have just a bunch of controls, there’s not much logic and just a few data fields you don’t have to worry much about Modularization.
However, if you’re building a whole application things will quickly change - the markup grows and grows with some undesired effects on productivity:
Luckily Fore has several ways of dealing with this. You don’t need a detailed plan upfront, but can use one of the features below to modularize when time has come.
Starting with the easiest method of factoring out a block of markup and loading it from an external file:
<fx-fore src="hello.html"></fx-fore>
When the browser hits the fx-fore
element it will first look for a src
attribute and if present, load the external page.
The page is searched for the first fx-fore
element which gets extracted and replaces the original fx-fore
element.
Please note that this approach allows to develop a standalone page and make it work individually and later use the unmodified page included in some other page. WARNING: please be aware that the CSS of the loaded page is not imported as just the
fx-fore
element is extracted. That could be a future enhancement.
As a consequence the import of the external file is always happening and cannot be cancelled or (directly) reverted. Using
<fx-fore src="mypage.html">
can be thought of as a simple include. It’s fine to break down larger pages into
smaller units but does not offer support for reducing the page load.
All attributes and CSS classes given to a fx-fore
element will be passed down to the replacing element.
For easy access to these attributes from within the loaded page there is the fore-attr()
function.
<fx-fore src="hello1.html" class="myClass" attr1="world"></fx-fore
Fore element in hello1.html:
<fx-fore>
Hello {fore-attr('attr1')}
</fx-fore>
If you inspect the live demo with devtools you’ll see that myClass
and attr1
are preserved.
You’ll see an additional attr ‘from-src’ which contains the value of the original
src
attribute. This is not of significance for now but might get used in the future.
A fx-fore
element can be used as a control like this:
<fx-fore>
...
<fx-control ref="item" url="myForeControl.html">
<label>A nested Fore acting as control</label>
</fx-control>
...
</fx-fore>
At runtime this will be expanded to this:
<fx-fore>
...
<fx-control ref="item" url= "myForeControl.html">
<label>A nested Fore acting as control</label>
<fx-fore class="widget">
<!-- content of myForeControl.html -->
</fx-fore>.
</fx-control>
...
</fx-fore>
There are no restrictions regarding the complexity or size of the embedded ForeBody.
for Web Components experts: Fore lives by default in the lightDOM but still restricts its events to the respective scope of a
fx-fore
element. Styling therefore can be applied globally. By adding a boolean attributeshadow
the loaded content will be put into shadowDOM. Usually that is NOT what you want when assembling a larger UI from parts.
To be useful there needs to be a way to pass in initial data for the embedded Fore. This is accomplished with the initial
attribute.
<fx-control ref="item" url="myForeControl.html" initial=".">
<label>A nested Fore acting as control</label>
</fx-control>
initial
is an XPath expression that resolves relative to the ref
node. Here (wich is a common case) we just pass
in the node that we are binding to in our outer ForeBody.
After the Fore control has initialized it will get the following default instance.
<fx-instance>
<data>
<item>[value of bound node in outer ForeBody]</item>
</data>
</fx-instance>
The embedded ForeBody can now work with this data as usual.
When an fx-control
embeds a ForeBody it will start listening
for a return
event.
Whenever the embedded ForeBody decides to be done (on value-changed
in example below) it will fire
the return
event passing back the resulting data in the nodeset
property. The control will use that and mount
the data to its binding. Let’s assume the user typed ‘result’:
<fx-fore>
<fx-model>
<fx-instance>
<data>
<item>result</item>
</data>
</fx-instance>
<fx-model>
<fx-control ref="item" url="myForeControl.html" initial=".">
<label>A nested Fore acting as control</label>
<fx-fore>
<fx-control ref="item">
<label>Your item</label>
<fx-return event="value-changed" ref="."></fx-return>
</fx-control>
</fx-fore>
</fx-control>
The returned data can be element nodes, an attribute node or text nodes and replace the bound node of the control.
This means that complete subtrees of data can be mounted back into the outer Fore.
<data>
<!-- this data do not match the above example - just for illustration -->
<item instock="true">
<article-number>1234</article-number>
<name>Sneeeaakr</name>
</item>
</data>
Warning: this feature is limited to the use of HTML or XML as data model. JSON support is still limited though planned for the future.
Using nested Fore elements like this the most powerful technique to modularize applications into smaller functional pieces. A ‘control’ can handle arbitrary complex logic within itself and only present the results back to its outer Fore. Existing ForeBodies can be embeded within another with minimal effort and still stay independent pages that can be developed and tested separately.
For bigger applications you probably want to limit the pageload as this often involves optional or dynamic views that you ideally only want ’to pay for’ when really needed.
You can also just start with minimal UI and load everything dynamically.
With the fx-load
action a lot of different scenarios can be accomplished and i’ll not going into navigational features
of the load action here, as these are well documented in the load demo.
For modularization purposes fx-load
offers two options:
A fx-load
action specifying an HTML template
element is useful if you have rather small snippet of HTML content
to insert into your UI.
As all actions fx-load
reacts to a certain event and it depends on your use case which one to choose.
<fx-load attach-to="#lazyControl" id="first" event="anyEvent">
<template>
<fx-control ref="item">
<label>an item:</label>
</fx-control>
<fx-output ref="item"></fx-output>
</template>
</fx-load>
<div id="lazyControl"></div>
The template may contain any kind of HTML including of course all Fore elements.
When the event fires the fx-load
action will clone the template and insert it into the DOM at the
position specified by attach-to
. It expects an id given in CSS selector syntax starting with a ‘#’.
The content of the target element will be replaced with the cloned template content.
<div id="lazyControl">
<fx-control ref="item">
<label>an item:</label>
</fx-control>
<fx-output ref="item"></fx-output>
</div>
If bigger chunks of content shall be loaded or you like to keep the content in a separate file, you can use the
url
attribute.
<fx-fore>
<fx-load event="ready" url="load-snippet.html" attach-to="#thetarget"></fx-load>
<fx-message event="loaded">url {event('url')}</fx-message>
<div id="thetarget"></div>
</fx-fore>
Inserting a full HTML page into another breaks the page and must be avoided. Thus, the content of the body
is used
for insertion at attach-to
node.
However if the loaded content contains another fx-fore
element it is assumed that this should be loaded instead.
When content became available fx-load
will fire a loaded
event in case some post-import actions need to be done.
To unload content and remove it from DOM again, the load action can simply provide a template with an empty HTML element.
As the content replaces the content of the target element, this will effectively remove whatever there has been before.
<fx-load attach-to="#lazyControl" event="anyEvent">
<template><div></div></template>
</fx-load>
<div id="lazyControl"></div>
<fx-fore src="myfore.html">
<fx-control url="myfore.html">
is helpful to break things down<fx-load>
Of course these approaches can also be combined.