A core concept in Skylight is the ability to bind view and card properties to data. In its simplest form, binding to data has two steps:
This two-step process works well when the data context’s values can map directly to the desired properties used in the data binding. However, if the data context needs to be altered in some way, we can use adapters.
What are adapters?
Adapters take the specified data context as an input and outputs a new data context on which the data binding will operate. This means that using an adapter inserts a step in between the two steps, so that the resulting three steps in binding to data looks like:
Within Application Builder, you can view your data binding logic directly in the content window.
When are adapters used?
There are four main reasons for why we would want to alter the data context. These are:
- Filtering lists
- Showing and hiding cards
- Modifying objects
- Retrieving asynchronous information
Binding a card to a list generates one card for each item in the list. Adapters enable us to filter the initial data context so that we only generate cards for items that pass our filter.
One example of such an adapter is one that filters a list of sessions. Without adapters, we can bind to our list of sessions, which will generate a card for each of our sessions. With an adapter, we can filter for sessions that have a specific property, such as those that are ready for review by a manager. This will then generate cards only for those particular sessions.
Showing and hiding cards
There are instances when showing or hiding a card based on some context is the desired effect. If an adapter returns null or undefined, a card will not be generated. Otherwise if the adapter returns an object (even if it’s an empty object), a card will be generated. We can use this knowledge to show and hide cards using the desired logic.
As an example, we can use an adapter to show a card if the user has the Manager application role or hide the card otherwise. Using the user’s information as the context, we can then check to see if the user has the Manager application role. If the user has this role, we return an empty object from the adapter. If the user doesn’t have this role, we return null from the adapter, which will cause the card to not be generated.
We can use adapters to process objects so that we can keep our data binding template free of complex logic. Given either a list of objects or a single object as the initial context, the adapter can add new properties to the object or alter existing ones.
An example of modifying objects in an adapter is adding a display name property to a user object, which the data binding template can then use to display the user’s name. To do this, the adapter first creates a copy of the user’s information (as the user’s information is read-only when retrieved from Skylight). Then, if the user has a first name and/or last name specified, the adapter will set the display name based on these values. If the user doesn’t have a first name or last name specified, the adapter will instead use the user’s username as the display name. This new object with the user’s display name as well as the user’s other properties is then used by the data binding to display the user’s name. While generating the display name based off of the first and last name (or username) is possible without using an adapter, adapters make it much easier to develop and maintain this logic.
Retrieving inaccessible data
Adapters can also ignore the initially-provided data context and simply return a completely new data context. This is useful for providing data contexts that are not available otherwise. At the time of writing this blog, there are two types of data contexts that fit into this category. Those that are only available asynchronously (such as a list of all users) and those that are only available in the globally-shared object. While adapters can be used to set these as data contexts, it is important to note that it is generally advised against doing so because updates to these data sources do not cause data bindings to refresh.
While most data is available synchronously and can be used as the initially-provided data context, the list of users is currently only available asynchronously. As such, an adapter that returns the list of (perhaps filtered) users will make an awaited call to retrieve the list of all visible users, then return that list as the new data context.
Use adapters wisely
In many cases, data binding can be performed directly on the initially-provided data contexts. However, we’ve seen that there are certain cases in which this is difficult or impossible. These are the cases in which adapters save the day by enabling us to filter and modify data contexts, as well as create new ones.