Transform API arguments with transformArgs
Transforms shape both what users see and what the backend receives. Use transform to format data before it renders. Use transformArgs when the user enters values that require conversion before the system makes a backend request. This gives you control over query logic, letting you normalize input strings, map readable labels to enum values, or inject state-based filters.
Understand transform vs. transformArgs
Use transform to change backend data before rendering it in the UI. Use transformArgs to change UI input before sending it to the backend.
If a user types "Active" into a filter:
transformArgsmaps "Active" to 0, the backend enum.The backend fetches data where
status= 0.transformmaps 0 back to "Active" before the UI renders it.
Use both functions to support backend logic while keeping the UI readable.
Prepare the dataset and entity
The following tabs show the entity and dataset required for this example. The status field stores an enum as a number, which the UI maps to a readable label.
This entity defines the WindTurbine structure used in the filter and backend query.
entity type WindTurbine {
manufacturer: string
location: string
manufacturerDate: datetime
status: int
}Configure the data grid to use the transform
Reference the transform in your UI component. This applies transformArgs during fetch and transform to format the result.
/* 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 sets up the transform. Once you reference the transform in the UI, define the Type and implement the transformArgs logic.
Define the transform Type
Create a transform that supports both transformArgs. The backend expects numeric status values. The UI displays readable strings.
// examplePackage/src/entity/WindTurbineDataTransform.c3typ
@typeScript
type WindTurbineDataTransform mixes UiSdlDataTransform<FetchResult<WindTurbine>, FetchResult<WindTurbine>>, Value {
transformArgs: ~ ts-client
}Implement the transformArgs function
Start with a basic transformArgs function that rewrites a single input. In this example, the UI passes a readable status label, such as "Active". The backend expects a numeric enum instead. This transform converts the label to the correct enum value before sending the query.
This example does not use component state or Redux. It shows how to manipulate the args object directly.
// examplePackage/src/entity/WindTurbineDataTransform.ts
// Define the transformArgs function to modify query arguments before sending them to the backend
export function transformArgs(
args: Record<string, any> // The arguments passed into the backend method
): Record<string, any> {
// Define a mapping from readable labels to backend enum values
const statusMap = {
active: 0,
inactive: 1,
maintenance: 2,
};
// Simulates a value entered in the UI near the input assignment
const input = "active";
// Look up the enum value that corresponds to the user-entered label
const enumValue = statusMap[input];
// If the label does not match any known value, return the arguments unchanged
if (enumValue === undefined) return args;
// Return a new arguments object with the enum value under the expected field name
return {
...args,
status: enumValue,
};
}This example uses a static argument. In the next example, you can pass dynamic values from component state.
Using component state
This function modifies the outgoing request before it reaches the backend. It reads the current input from component state, maps that value to an enum, and appends the correct filter to the query. This ensures that readable UI input like "Active" gets translated into the backend's expected value.
// examplePackage/src/entity/WindTurbineDataTransform.ts
// Import required types: the result wrapper, the WindTurbine entity, and Redux state
import { FetchResult, WindTurbine, UiSdlReduxState } from '@c3/types';
// Import a helper that retrieves component-level configuration from Redux state
import { getConfigFromState } from '@c3/ui/UiSdlConnected';
// Define the transformArgs function to rewrite query arguments before calling a backend action
export function transformArgs(
searchArguments: Record<string, any>, // Existing arguments that will be sent to the backend
componentId: string, // The component ID to identify the relevant UI element
state: UiSdlReduxState // The global Redux state that holds UI component values
): Record<string, any> {
// Retrieve the current value from the component state (e.g., what the user typed or selected)
const searchQuery = getConfigFromState(componentId, state, ['value']);
// Define a reverse mapping from human-readable UI labels to backend enum values
const statusEnumReverseMap = {
active: 0,
inactive: 1,
maintenance: 2,
};
// Specify the field that the filter will target in the backend query
const fieldName = 'status';
// Exit early if the user did not input a value
if (!searchQuery) return searchArguments;
// Normalize and map the UI label to its corresponding enum value
const enumValue = statusEnumReverseMap[searchQuery.toLowerCase()];
// Exit if the input does not match a valid status
if (enumValue === undefined) return searchArguments;
// Build the filter expression that checks for the enum value as a string match
const newFilter = `contains(lowerCase(string(${fieldName})), "${enumValue}")`;
// If an existing filter exists, append the new filter using logical OR
if (searchArguments?.spec?.filter) {
searchArguments.spec.filter += ' || ' + newFilter;
} else {
// If no filter exists, create a new spec block with the filter
searchArguments.spec = {
...searchArguments.spec, // Preserve any existing keys
filter: newFilter,
};
}
// Return the modified query arguments
return searchArguments;
}This implementation allows users to filter the data grid using labels like "Active", while still sending valid enum filters to the backend.