Custom vs Script Component Part - The general rule of thumb is that Script tags are for custom, component-specific behavior, or to fill in gaps in stitching together other Component Parts, while writing Custom Component Parts is for interfacing with async, APIs, or any time that a Script Component Part gets too cumbersome. Modulo's philosophy is to allow separation of work between component development (HTML, CSS, templating, and high-level behavior), and Component Part development (complex JavaScript and APIs).
Script
Script Component Parts allow you to define custom behavior for components using the full power of JavaScript. The most common use of Script tags is to add more sophisticated interactive behavior. Instead of just relying on premade Component Parts, with a Script tag you can program any custom behavior into your component.
Typical use
The most common use of a Script Component Part is to specify custom JS code. See below for a simple example:
Event callbacks
The most common purpose of a Script Component Part is to add custom behavior when certain "events" occur to your component. Consider the following example of 3 click events:
In this, the Script Component Part defines a function named countUp. The on.click=
attribute on the button utilizes directives to attach a "click event" to the
button, such that when a user clicks on that button it will invoke the
countUp function.
From within event callbacks, the Script Component Part exposes the current renderObj as variables. So, state by itself is equivalent to renderObj.state. This enables us to directly modify the state by simply doing state.count++. By default, components rerender after every event, so after the event the component will rerender and visually reflect the state changes.
This means that all renderObj variables will be available here, in a similar way to how Template exposes them: For example, you can use code like props.XYZ to access data from a Props Component Part.
You can also access the JavaScript Object instances of the Component Part Class. To access those, you use the cparts
Finally, the variable element will refer to the HTML element of the current component. This is useful for direct DOM manipulation or interfacing with other frameworks or "vanilla" JavaScript. Generally, however, you should avoid direct DOM manipulation whenever you can, instead using a Template Component Part to render the component (otherwise, the Template will override whatever direct manipulation you do!).
DOM references
script.ref
Using script.ref, we can get easy access to DOM elements. See below for
examples:
Example 1: Using script.ref to focus input
Example 2: Script.ref naming and drilling down
Using a suffix we can provide a custom name. For example, the directive
script.ref.firstname becomes ref.firstname.
By specifying a value, we can "drill down" to properties of the element. For
example, to access the built in style attribute, you can do
script.ref=style.
Lifecycle callbacks
By naming functions with certain names, you can "hook into" the component rendering lifecycle with callbacks.
You can define a function with any of the following names and expect it to be
invoked during it's namesake lifecycle phase: initializedCallback,
mountCallback, prepareCallback, renderCallback, domCallback,
reconcileCallback, and finally updateCallback.
See below for an example of defining a custom prepareCallback in order to
"hook into" the component rendering lifecycle to execute custom code. The
return value of this function is available to the Template Component Part when it
renders during the render lifecycle.
Example 1: prepareCallback
Example 2: All callbacks
Template literals? The back-tick syntax is template literals.
Manual HTML creation with Script
Template vs renderCallback Before replacing a Template with a
renderCallback, first consider using prepareCallback or extending the templating language with a custom filter. The Templating language is intentionally limited and result in more readable code and a cleaner separation of concerns of logic (JavaScript) from presentation (HTML templates).
You can use Script as a Template replacement, if necessary. For
fine-grained control over a component's rendered HTML, you can hook into the
renderCallback. While not recommended for most usage, it remains an option
to use the renderCallback to write JS that constructs the HTML in a custom
fashion, such as using a third party templating system, or simply using
template literals.
For even greater control, you can simply replace the innerHTML of the entire
element. This will skip any virtual DOM or reconciler. Thus, we don't have
access to click events or binding, making many features less useful. Also note
that we can't use "onkeyup" but instead use "onchange" -- using the built-in
element.innerHTML causes the input to lose focus, otherwise. Nonetheless,
it's still usable, and might be a useful example for fine-grained control.
See below for both examples: