Transform Data for UI Components Using Transforms
A transform lets you modify data before the UI displays it. You define a transform as a Type that mixes UiSdlDataTransform and implements the transform function. This function takes the raw data from the backend and returns a modified version for the UI.
Use a transform when the backend data doesn't match how you want it to appear in the UI. You might want to format a date, clean up a string, or convert a status code into a readable label. A transform gives you full control over the data before the component renders it.
Transforms improve UI clarity, reduce the need for frontend workarounds, and ensure consistency across components. You can chain multiple transforms together in the dataTransforms array to build a transformation pipeline. This approach lets you break down complex logic into smaller, focused transforms and apply them in sequence.
Prepare the dataset for the transform
The WindTurbine examples in this topic rely on both a data model and a matching dataset. If you want to follow along with the examples in this topic, create the following entity Type and seed it with the matching dataset. The transform logic expects the entity structure and data format shown below.
This entity defines the structure of the WindTurbine Type. The transform logic expects each object to follow this schema.
entity type WindTurbine {
/**
* The manufacturer of the wind turbine.
*/
manufacturer: string
/**
* The location of the wind turbine.
*/
location: string
/**
* The manufacturer date of the wind turbine.
*/
manufacturerDate: datetime
/**
* The of the wind turbine turbine.
*/
status: int
}How to use a transform
To use a transform, follow two steps. First, define a Type and write the function that applies your data transformation logic. Then, configure your UI component to use that Type.
In this example, you define a transform Type called WindTurbineDataTransform. Start by updating your component configuration to reference it. You implement the logic in a later section.
Here is an example that applies the WindTurbineDataTransform to a UiSdlDataGrid component:
/* examplePackage/ui/c3/meta/examplePackage.WindTurbineGrid.json */
{
"type": "UiSdlConnected<UiSdlDataGrid>",
"component": {
"header": {
"title": "Wind Turbine Dataset"
},
"paginationConfig" : {
"pageSize" : 2,
"pagination" : true
},
"dataSpec": {
"dataType": "WindTurbine",
"dataTransforms" : [ "WindTurbineDataTransform" ],
"columnFields": [{
"fieldName": "id",
"label": "ID"
}, {
"fieldName": "location",
"label": "Location"
},{
"fieldName": "manufacturer",
"label": "Manufacturer"
},{
"fieldName": "manufacturerDate",
"label": "Manufacturer Date"
}, {
"fieldName": "status",
"label": "Status"
}]
}
}
}This configuration connects the component to the WindTurbine entity and applies the transform to the data before it displays. Once you reference the transform in the UI, define the Type and implement the logic to shape the data. The next sections show how to do that.
How to create a transform
A transform is a Type that mixes in UiSdlDataTransform and implements the methods required to modify data.
To define a transform:
- Create a new Type
- Mix in UiSdlDataTransform
- Override the transform method
- Implement the method with your custom data transformation logic
The following example defines a WindTurbineDataTransform Type that sets up the structure for a transform:
// examplePackage/src/entity/WindTurbineDataTransform.c3typ
@typeScript
type WindTurbineDataTransform mixes UiSdlDataTransform<FetchResult<WindTurbine>, FetchResult<WindTurbine>> {
transform: ~ ts-client
}In this example, the UiSdlDataGrid component uses the WindTurbineDataTransform Type to transform its data. When the component fetches data, it calls WindTurbine.fetch() on the backend. That method returns data of FetchResult<WindTurbine>. Because UiSdlDataGrid expects its data in the shape of FetchResult, the transform must also return a value of that Type. Define the transform with matching input and output types.
Here is an example of how you can define the WindTurbineDataTransform Type:
// examplePackage/src/entity/WindTurbineDataTransform.c3typ
@typeScript
type WindTurbineDataTransform mixes UiSdlDataTransform<FetchResult<WindTurbine>, FetchResult<WindTurbine>> {
transform: ~ ts-client
}Transform implementation
In the TypeScript file for this Type, implement the transform function. Use it to format dates and map status codes to readable labels.
// examplePackage/src/entity/WindTurbineDataTransform.ts
// Imports the necessary types: FetchResult and WindTurbine from a shared type library
import { FetchResult, WindTurbine } from '@c3/types';
// Define a mapping from enum values to human-readable strings
const statusMapping = {
0: 'Active',
1: 'Inactive',
2: 'Maintenance',
};
/**
* Transforms WindTurbineData to modify the date format.
* Accepts a FetchResult containing WindTurbine objects,
* formats the `manufacturerDate` into a human-readable string,
* and returns the transformed result.
*/
export function transform(
fetchResult: FetchResult<WindTurbine>
): FetchResult<WindTurbine> {
// Check if there are any WindTurbine objects in the result
if (fetchResult.objs) {
// Loop through each WindTurbine object in the array
fetchResult.objs.forEach((turbine) => {
// Format the manufacturerDate field into a human-readable string
turbine.manufacturerDate = formatHumanReadableDate(turbine.manufacturerDate);
// Format the installationDate field as well
turbine.installationDate = formatHumanReadableDate(turbine.installationDate);
// Add a new field called statusName with the readable status label
turbine.status = statusMapping[turbine.status];
});
}
// Return the modified FetchResult
return fetchResult;
}
// Formats an ISO date string into a human-readable format like "April 20, 2024"
function formatHumanReadableDate(dateString: string): string {
// Converts the input string into a JavaScript Date object
const date = new Date(dateString);
// Defines the desired output format: "Month Day, Year"
const options: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "long",
day: "numeric",
};
// Returns the date string formatted according to the user's locale
return date.toLocaleDateString(undefined, options);
}This function transforms the raw backend data before the UI renders it. It replaces numeric status codes with readable labels, and it reformats ISO date strings into human-friendly formats. When the UI component fetches data, this logic ensures that every record appears clean and readable — without requiring additional formatting in the component itself.