Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Aurelia 2’s templating system offers a powerful and intuitive way to build and manage the user interface of your web application. It goes beyond the traditional boundaries of HTML, infusing it with enhanced capabilities to create dynamic and interactive user experiences. At the heart of Aurelia 2's templating is the seamless connection between your HTML templates and the underlying JavaScript or TypeScript code, enabling a responsive and data-driven UI.
In Aurelia 2, templates are not just static HTML files. They are dynamic views that interact with the underlying logic of your application, responding to user actions and data changes. This integration makes your development process more efficient, allowing you to build complex UIs with less code and greater clarity.
From the moment you scaffold a new Aurelia 2 project, you engage with templates that are both familiar in their HTML structure and powerful in their extended functionality. Whether defining the layout for a new component or displaying data in your HTML, Aurelia 2's templating syntax is designed to be both developer-friendly and highly expressive.
Two-Way Data Binding: Aurelia's robust data binding system ensures a seamless data flow between your application’s model and the view, keeping both in sync without extra effort.
Custom Elements and Attributes: Extend your HTML with custom elements and attributes that encapsulate complex behaviors, promoting code reuse and modularity.
Adaptive Dynamic Composition: Dynamically render components and templates based on your application's state or user interactions, enabling the creation of flexible and adaptive UIs.
Rich Templating Syntax: Utilize Aurelia's powerful templating syntax for iterating over data, conditionally rendering parts of your UI, and easily handling events.
Expression and Interpolation: Effortlessly bind data to your templates and manipulate attributes with Aurelia’s straightforward expression syntax.
Template references in Aurelia 2 provide a powerful and flexible way to connect your HTML templates with your JavaScript or TypeScript view models. Using the ref attribute, you can easily identify and interact with specific parts of your template, making it more efficient to manipulate the DOM or access template data.
Add the ref attribute to an HTML element within your template to create a template reference. This marks the element as a reference, allowing you to access it directly in your view model.
In this example, myInput
references the input element, which can be used both in the template and the corresponding view model.
Template references are immediately available within the template. For instance, you can display the value of the input field as follows:
This binding displays the current value of the input field dynamically.
To access the referenced element in the view model, declare a property with the same name as the reference. For TypeScript users, it's important to define the type of this property for type safety.
Aurelia's ref
attribute is not limited to standard HTML elements. It can also be used with custom elements and attributes to reference their component instances (view-models) or controllers.
Custom Element Instance Use component.ref="expression"
to create a reference to a custom element's component instance (view-model). This was known as view-model.ref
in Aurelia v1.
Custom Attribute Instance Similarly, custom-attribute.ref="expression"
can reference a custom attribute's component instance (view-model).
Controller Instance For more advanced scenarios, controller.ref="expression"
creates a reference to a custom element's controller instance.
Template references are incredibly useful for integrating with third-party libraries or when direct DOM manipulation is necessary. Instead of using traditional JavaScript queries to find elements, template references provide a more straightforward, framework-integrated approach.
Leveraging template references can greatly simplify interactions with elements, particularly when integrating with libraries that require direct DOM element references. This approach promotes cleaner and more maintainable code by reducing reliance on direct DOM queries.
Event binding in Aurelia 2 provides a seamless way to handle DOM events within your application. By attaching event listeners directly in your view templates, you can easily respond to user interactions such as clicks, key presses, and more. This guide will delve into the specifics of event binding in Aurelia 2, offering detailed explanations and examples to enhance your understanding and usage of this feature.
Aurelia 2 simplifies the process of binding events to methods in your view model. It uses a straightforward syntax that allows you to specify the type of event and the corresponding method to invoke when that event occurs.
The general syntax for event binding in Aurelia 2 is as follows:
element
represents the HTML element to which you want to attach the event listener.
event
is the event you want to listen for (e.g., click
, keypress
).
.trigger
is the binding command that tells Aurelia to listen for the specified event and call the method when the event is fired.
methodName
is the method's name in your view-model that will be called when the event occurs.
argument1
, argument2
, ... are optional arguments you can pass to the method.
Aurelia 2 offers two primary commands for event binding:
.trigger
: This command attaches an event listener that responds to events during the bubbling phase. It is the most commonly used event-binding command and is suitable for most use cases.
.capture
: This command listens for events during the capturing phase. It is generally reserved for special circumstances, such as when you need to intercept events before they reach a target element that may prevent their propagation.
To listen for a click event on a button and call a method named handleClick
, you would write:
When the button is clicked, your view-model's handleClick
method will be executed.
You can pass the event object itself or other custom data to your event handler method. For instance, to pass the event object to the handleClick
method, you would modify the binding like this:
In your view model, the handleClick
method would accept the event object as a parameter:
Aurelia 2 allows you to bind to any standard DOM event. Here are some common events you might use:
The click
event is frequently used for buttons, links, and other clickable elements.
The keypress
event is useful for responding to user input in text fields or when handling keyboard navigation.
The mouseover
event can trigger interactions when the user hovers over an element.
Sometimes, you may want to stop an event from bubbling up the DOM tree or prevent the default action associated with that event. You can do this within your event handler methods using the event object's methods:
event.stopPropagation()
: Prevents further propagation of the event in the bubbling or capturing phase.
event.preventDefault()
: Cancels the event if it is cancelable without stopping further propagation.
While the .trigger
and .capture
commands cover most use cases, Aurelia 2 also allows for more advanced scenarios, such as throttling event handlers for performance reasons or handling custom events.
To improve performance, especially for events that can fire rapidly like mousemove
or scroll
, you can throttle the event handler invocation using Aurelia's binding behaviors.
In the above example, the handleMouseMove
method will be called at most once every 100 milliseconds, no matter how often the mousemove
event is fired.
Aurelia 2 supports custom events, which can be useful when integrating with third-party libraries or creating your own custom components.
In this example, my-event
is a custom event emitted by custom-element
, and handleCustomEvent
is the method that will respond to it.
To help you better understand event binding in Aurelia 2, we've compiled a collection of examples and scenarios demonstrating different techniques and best practices. These should give you the insights to handle events in your applications effectively.
To ensure that an event only triggers a method if the event originated from the element itself (and not from its children), you can use the self
binding behavior.
This setup guarantees that clicking the button will not trigger the divClicked()
method, as the self
binding behaviour filters out events bubbling from child elements.
A checkbox's change in state can be combined with the change
event to perform actions in response to user interaction.
To react to specific key presses, such as "Enter" or "Escape", you can inspect the event
object within your method.
Event delegation is useful for handling events on dynamically generated content, such as a list of items.
Custom elements can publish custom events with associated data, which parent components can listen for and handle.
Custom element:
Parent component:
Parent view-model:
For features like search or autocomplete, where user input can trigger frequent updates, throttling can prevent excessive processing.
Here, the search
function is called only after the user has stopped typing for 300 milliseconds, improving performance and user experience.
These examples showcase the versatility of event binding in Aurelia 2. By understanding and applying these patterns, you can create interactive and efficient applications that respond to user actions in a controlled and performant manner.
When you need to ensure some conditions are met before processing an event, you can use event modifiers. Event modifiers can be specified via event syntax, follow by a colon and modifiers:
By default, Aurelia handles 2 set of common events: mouse and keyboard events. An example is as follow:
In the example above, the handler onCtrlClick()
will only be called when the button is clicked while the Ctrl
key being pressed. Keyboard event sometimes employ even more complex condition, as per the following example:
In this example, we will only call send()
when the user hits the Enter
+ Ctrl
key combo. This example also demonstrates how to use multiple modifiers, they can be separated by the character +
as delimiter.
preventDefault
and stopPropagation
are two functions commonly called on any events. Event modifiers can be used to declaratively and easily call those functions, as per following example:
When handling mouse event, it sometimes requires a specific mouse button. By default, Aurelia provides 3 modifiers left
, middle
and right
to support mouse button verification. An example is as follow:
When using keyboard event modifier, sometimes a certain key is used as modifier. You can use the char code representing the key as the modifier, like the following example, where we want to handle the combo Ctrl + K
(notice its the upper K
):
75
is the charcode of the upper case letter K
.
Even though direct, it's not always clear 75
means when looking at the template, so it's often desirable to use the real letter K
instead. Though Aurelia is not taught to, by default, understand the letter K
means the code 75
. You can teach Aurelia by adding to the IKeyMapping
:
After this enhancement, the :ctrl+upper_k
modifier will be understood as ctrl+75
or ctrl
+ upper K
key.
Note that we cannot use the upper case letter K
as modifier in HTML because HTML is case insensitive. We use, in this example, upper_k
as an alternative for that, and add the mapping accordingly.
By default, Aurelia provides mapping for all lower case a-z letters in both keycode and leter so both :ctrl+a
and :ctrl+97
works. For upper case letter, only keycode mapping is provided, for example: :65
for upper letter A works.
Event binding in Aurelia 2 is a powerful and intuitive feature that enables you to create dynamic and responsive applications. By understanding the syntax and capabilities of event binding, you can harness the full potential of Aurelia 2 to handle user interactions gracefully and effectively. Remember to leverage the .trigger
command for most scenarios and reserve .capture
for special cases where you need to intercept events earlier in the event propagation cycle. With these tools, you can craft a seamless user experience that responds to every click, keypress, and interaction.
In your view templates, you can specify inline variables using the <let>
custom element.
The <let>
element supports working with interpolation strings, plain strings, referencing view model variables, and other let bindings within your templates.
You could then display this value using its camelCase variant:
You can bind to variable values in a <let>
too:
Attribute binding in Aurelia is a powerful feature that allows you to bind to any native HTML attribute in your templates. This enables dynamic updates to element attributes such as classes, styles, and other standard HTML attributes.
The basic syntax for binding to attributes in Aurelia is straightforward:
You can bind to almost any attribute listed in the comprehensive HTML attributes list, which can be found here.
Aurelia provides multiple methods for attribute binding, each with its syntax and use cases.
Interpolation allows for embedding dynamic values within strings. Here's an example using interpolation to bind the id
attribute:
Aurelia supports several binding keywords, each defining the data flow between the view model and the view:
one-time
: Updates the view from the view model once and does not reflect subsequent changes.
to-view
/ one-way
: Continuously updates the view from the view model.
from-view
: Updates the view model based on changes in the view.
two-way
: Creates a two-way data flow, keeping the view and view model in sync.
bind
: Automatically determines the appropriate binding mode, defaulting to two-way
for form elements and to-view
for most other elements.
Binding image attributes, such as src
and alt
, is as simple as:
Bind to the disabled
attribute to disable buttons and inputs dynamically:
Choose between innerhtml
for rendering HTML content and textcontent
for text-only content:
Aurelia uses a mapping function to convert properties to HTML attributes. The attribute mapper handles the conversion, typically changing kebab-case to camelCase. However, not all properties map directly to attributes.
.attr
TagIf automatic mapping fails, use .attr
to ensure proper attribute binding:
Apply the attribute binding behavior with .bind
and & attr
to specify the binding type:
Remember, interpolation and keyword binding achieve similar results, and there should be no noticeable difference in performance or features. Choose the syntax based on your preference and the specific requirements of your project.
Text interpolation allows you to display values within your template views. By leveraging ${}
, a dollar sign followed by opening and closing curly braces, you can display values inside your views. The syntax will be familiar to you if you are familiar with template literals.
Interpolation can be used to display the value of variables within your HTML templates, object properties and other forms of valid data.
To show how interpolation works, here is an example.
Notice how the variable we reference in our HTML template is the same as it is defined inside of our view model? Anything specified on our view model class is accessible in the view. Aurelia will replace ${myName}
with Aurelia
think of it as a fancy string replacement. All properties defined in your view model will be accessible inside your templates.
A template expression allows you to perform code operations inside of ${}
we learned about earlier. You can perform addition, subtraction and even call functions inside of interpolation.
In the following simple example, we are adding two and two together. The value that will be displayed will be 4
.
You can call functions with parameters if you have a function inside your view model.
You can also use ternaries inside of your interpolation expressions:
Also supported in template expressions is optional syntax. Aurelia supports the following optional syntax in templates.
??
?.
?.()
?.[]
While Aurelia supports a few optional syntaxes, ??=
is not supported.
Using optional syntax and nullish coalescing allows us to create safer expressions without the need for if.bind
or boilerplate code in view models.
This can help clean up what otherwise might have been long and complex ternary expressions to achieve the above result.
You would be forgiven for thinking that you can do pretty much anything that Javascript allows you to do, but there are limitations in what you can do inside of interpolation you need to be aware of.
Expressions cannot be chained using ;
or ,
You cannot use primitives such as Boolean
, String
, instanceOf
, typeof
and so on
You can only use the pipe separator |
when using value converters but not as a bitwise operator
In Aurelia 2, templates are designed to limit direct access to global variables like window
or document
for security reasons. However, there are scenarios where access to certain global variables is necessary. Aurelia allows access to a predefined list of global variables commonly used in development.
To reduce boilerplate, Aurelia allows template expression to access a fixed list of global variables that are usually needed. Those globals are as follows:
Here are some examples of using globals inside of Aurelia templates. The usage is the same as it is inside of Javascript, except in your Aurelia templates.
Manipulate JSON data directly in your templates.
Perform calculations using the Math object.
isNaN
Display content conditionally based on numeric checks.
RegExp
Use the RegExp
constructor to create dynamic regular expressions for data validation or manipulation.
Object
Access properties dynamically on an object using the Object
constructor.
Set
Demonstrate set operations like union, intersection, or difference.
encodeURI
and decodeURI
Manipulate URL strings by encoding or decoding them.
Intl.NumberFormat
Format numbers using Intl.NumberFormat for localization.
Array
Demonstrate complex array manipulations, such as chaining methods.
Use Sparingly: Rely on global variables only when necessary. Prefer component properties and methods for data and logic.
Security: Be cautious of the data processed using global functions to prevent XSS attacks and other vulnerabilities.
Performance: Frequent use of complex operations like JSON.stringify in templates can impact performance. Consider handling such operations in the component class.
Reactivity: Remember that changes to global variables are not reactive. If you need reactivity, use component properties or state management solutions.
Aurelia 2 enhances the handling of promises within templates. Unlike Aurelia 1, where promises had to be resolved in the view model before passing their values to templates, Aurelia 2 allows direct interaction with promises in templates. This is achieved through the promise.bind
template controller, which supports then
, pending
, and catch
states, reducing the need for boilerplate code.
The promise.bind
template controller allows you to use then
, pending
and catch
in your view, removing unnecessary boilerplate.
The promise binding simplifies working with asynchronous data. It allows attributes to bind to various states of a promise: pending, resolved, and rejected.
The following example demonstrates a method fetchAdvice bound to the promise.bind
attribute. It uses then
and catch
to handle resolved data and errors.
The i
variable triggers a method call in the template, as Aurelia considers method calls pure and re-invokes them only if their parameters change.
This example can also be seen in action below.
The promise
template controller operates within its own scope, preventing accidental pollution of the parent scope or view model.
In this example, data
and err
are scoped within the promise controller. To access these values in the view model, use $parent.data
or $parent.err
.
Aurelia 2 supports nested promise bindings, allowing you to handle promises returned by other promises.
When using promise.bind
within a repeat.for
, it's recommended to use a let
binding to create a scoped context.
The above example shows usage involving repeat.for
chained with a promisify
value converter. Depending on the second boolean value, the value converter converts a simple value to a resolving or rejecting promise. The value converter in itself is not that important for this discussion. It is used to construct a repeat.for
, promise
combination easily.
The important thing to note here is the usage of let
binding that forces the creation of two properties, namely data
and err
, in the overriding context, which gets higher precedence while binding.
Without these properties in the overriding context, the properties get created in the binding context, which eventually gets overwritten with the second iteration of the repeat. In short, with let
binding in place, the output looks as follows.