Bounded Properties
The ElementController
and PageController
classes enable the definition of properties whose values are bound to a communication channel. These bindings can be of three types: inbound, outbound, or both.
Inbound properties: In this type, the property value is injected into the controller by the channel. This allows the controller to receive and use data updates from the channel.
Outbound properties: Here, the property value updates within the controller are published to the channel. This ensures that any changes made to the property within the controller are immediately propagated to all other components or systems subscribed to the channel.
Inbound & Outbound properties: A property can simultaneously have both inbound and outbound bindings. This means the property can receive updates from the channel and also publish its updates to the channel. This bidirectional communication ensures synchronization between the controller and the channel, maintaining consistency across the system.
By leveraging these binding mechanisms, ElementController and PageController facilitate dynamic and responsive data handling within the application, promoting efficient communication and state management.
The controller utilizes the web component lifecycle hooks connectedCallback
and disconnectedCallback
to manage the connection and disconnection of bound properties to their respective channels. When the component is added to the DOM, the connectedCallback
is invoked, allowing the controller to establish bindings for its properties to the designated channels. Conversely, when the component is removed from the DOM, the disconnectedCallback
is triggered, ensuring that the properties are properly disconnected from the channels, thus preventing memory leaks and unwanted data updates.
In the context of LitElement
, inbound properties can trigger a re-render by invoking Lit's requestUpdate
method. This mechanism ensures that any updates received from the channels are reflected in the component's UI, maintaining a seamless and dynamic user experience.
Declaring bounded properties
Permalink to “Declaring bounded properties”The bounded properties in the controller are declared using the static fields inbounds
and outbounds
.
For inbound properties, the inbounds
field specifies the following properties:
- channel: This mandatory property defines the name of the channel from which data is read.
- skipUpdate: This optional property, when set to true, prevents the triggering of requestUpdate on value changes. By default, it is set to false.
- action: This optional property is a function that processes the incoming value from the channel and returns a transformed value.
Example:
export class CategoryPage extends (LitElement) {
pageController = new PageController(this);
static inbounds = {
categoriesList: { channel: 'categories' },
likedRecipes: { channel: 'liked-recipes', action: (data) => data.recipes.filter(r => r.hasLikes ) },
};
For outbound properties, the outbounds
field includes:
- channel: This mandatory property specifies the name of the channel to which data is written.
Example:
export class CategoryPage extends (LitElement) {
pageController = new PageController(this);
static outbounds = {
likedRecipes: { channel: 'liked-recipes' },
};
A property can be declared in both the inbounds
and outbounds
fields, allowing it to be both read from and written to the respective channels.
Example:
export class CategoryPage extends (LitElement) {
pageController = new PageController(this);
static inbounds = {
likedRecipes: { channel: 'user-liked-recipes', action: (data) => data.recipes.filter(r => r.hasLikes ) },
};
static outbounds = {
likedRecipes: { channel: 'liked-recipes' },
};
Conclusion
Permalink to “Conclusion”As you can see, the bounded properties provided by ElementController
and PageController
offer a convenient and concise way to achieve the same functionality as using @property
or @state
with manual publish
and subscribe
mechanisms.
For instance, this example:
export class CategoryPage extends (LitElement) {
pageController = new PageController(this);
static inbounds = {
likedRecipes: { channel: 'liked-recipes' },
};
is equivalent to the following implementation:
export class CategoryPage extends (LitElement) {
pageController = new PageController(this);
@state()
protected _likedRecipes: Set<Recipe> | null = null;
connectedCallback() {
super.connectedCallback();
this.pageController.subscribe('liked-recipes', (data: Set<Recipe>) => {
this._likedRecipes = data;
this.requestUpdate();
});
}
disconnectedCallback() {
this.pageController.unsubscribe('liked-recipes');
super.disconnectedCallback();
}
};