Stages & Components: Widget
What are we learning here?
Stages & Components Relations: ┌──────────────────────┐
┌─optional────►│ Component Element(s) │
┌───────────────┐ ┌───────────┐ │ └──────────────────────┘
│ Initial Stage ├─load──►│ Component ├─provides─┤
└───────────────┘ └───────────┘ │ ┌──────────┐
▲ └─at least one─►│ Stage(s) │
│ └────┬─────┘
│ │
└ ─ ─ ─ ─ ─ ─ ─ ─ load ─ ─ ─ ─ ─ ─ ─ ─┘
System Hierarchy:
► Initial Stage
└► Root Component
└► Stage "main"
└► Application
└► Stage "main"
└► Widget
└► Component Element "main"
- How to create an component based on
Widget
- Use the component element to create a HTML structure
- Use template variables in our HTML structure
- Use a local scoped CSS
As we now know, every component has at least one main stage. This also applies to our application component. The main stage of an application component is the content area between tilte bar and border elements.
We now load another component into the main stage of our application component. Here too we have to
first to create a component. This time we will create a component based on the base component class
Widget
.
A component that extends the Widget
class creates a container in which you can implement arbitrary
user interfaces. For this purpose, the component provides a so-called "component element”. You can
load any HTML structure you want into a component element.
Best practice for shared and non-shared components
We put the files for the widget into the same directory as the application file. Components which will be used only by one application should be placed into the same folder.
If you plan to develop a reusable component, best practice would be to put all related files of
the component into a separate directory with a main file index.js
.
We will put the the widget interface HTML in a separate file and use template variables there.
Please note the .ejs.html
extension. This is important so that variables can be processed:
src/demo/apps/component-basics/content.ejs.html
1 |
|
We also put the CSS of the widget interface in a separate file and use a local scope. Please note
the .module.css
extension. This is important so that local scopes can be used:
src/demo/apps/component-basics/content.module.css
1 2 3 4 5 6 |
|
We can now import our HTML and our CSS file. The imported HTML and will be used as inner HTML of the
component element provided. The component element can be accessed via this.element
,
this.getElement()
, or in more verbose this.getElement("main")
.
Multiple component elements
A widget component only provides a single component element (named "main"). However, it is quite possible that other components provide several component elements with additional names, or none at all.
Here too we use the async start()
method, which is called in each component during its
initialization phase to fill the component element:
src/demo/apps/component-basics/content.js
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Always separate Structure, Style and Code
- Each component should always save the individual parts: HTML, CSS and JavaScript in separate files.
- You should always use a local scope in CSS. This converts the class names to unique id's and avoids collisions with other component styles.
Import EJS files
If we import files with the extension .ejs.html
, we get a function template()
so we can call
with the desired values of the variables. This function then returns the final HTML code.
Import CSS modules
If we import files with the extension .module.css
, we get an object with all classnames
defined with :local()
as properties. In our example we have defined the classname
:local(widget)
so we can access the localized classname with style.widget
.
It should be best practice to define one local name for the root of each component element. All other styles should be defined as nested classes.
Now load the widget into the main stage of our application. Again we will use the method load()
of
the main stage of the application for this, like we previously loaded our system into the initial
stage or the application into the system component.
Important: Loading a component is always asynchronous. So do not forget to wait for it with await
:
src/demo/apps/component-basics/index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Start Definition Object vs Shortcut Signature
Here we will use a signature of the load method which expects only one Component
. This is just
a shortcut signature. The load method normally expects a so called start definition object.
This would look like:
load({
component: ChildComponent
})
Now you should see the Header "Component Basics" in the main area of the application.