Custom card JavaScript API event system
The custom card JavaScript API provides a native interface for emitting and listening to application events. This event-driven model allows custom cards to implement Flux-like state management patterns, cleanly decoupling asynchronous operations (such as server data fetching) from UI view rendering.
By using this API, custom React components can attach and remove event listeners directly within lifecycle methods, eliminating the need for isMounted anti-patterns. This messaging pipeline can also be used to facilitate direct client-side communication between separate custom cards hosted on the same page.
API methods reference
addEventListener
Attaches an event listener callback function to a specified event type.
addEventListener(type: string, callback: function);
type(string): The unique identifier name for the event. Event types do not need to be declared prior to registration. Multiple listeners can be registered to the same event type.Best Practice: Use explicit, namespace-prefixed naming conventions to prevent naming collisions with other custom cards (e.g., prefer
'tfc-required-reading-update'over generic names like'update').
callback(function): The target function executed when the event is fired.Memory Management: You must explicitly remove any event listeners when the custom card component unmounts or is destroyed to prevent memory leaks.
removeEventListener
Deregisters a previously attached event listener callback.
removeEventListener(type: string, callback: function);
Parameters: Accepts the identical
typestring andcallbackfunction reference passed during initial registration.Safety: It is safe to call this method even if an active listener was not previously registered to the specified event type.
fireEvent
Dispatches an event payload to all active listeners registered to the matching event type.
fireEvent(type: string, arg1: any, arg2: any, arg3: any);
type(string): The targeted event name. Unlike traditional Flux action dispatchers, only listeners explicitly bound to this specific event type will be executed.arg1,arg2,arg3(optional): Data arguments passed directly to the listener callback function. Arguments are optional, and the method supports a maximum payload of 3 arguments.
Component implementation example
The following example demonstrates an asynchronous search request triggering a global event, which a React component listens to and consumes within its lifecycle:
var SearchResultsEventName = 'tfc-sweet-search-results';
// Asynchronous action that fires an event upon receiving response data
function createSearchAction(searchQuery) {
tf.api.newApiRequest('/api/search', searchQuery, 'POST', function (resp) {
ctx.customPortlets.fireEvent(SearchResultsEventName, resp.success, resp.data);
});
}
// React component consuming event payloads via lifecycle hooks
class TFC_SweetSearchResults extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
hasError: false,
results: [],
};
this.onSearchResults = this.onSearchResults.bind(this);
}
componentDidMount() {
// Register listener on mount
this.props.ctx.customPortlets.addEventListener(SearchResultsEventName, this.onSearchResults);
// Trigger search action
createSearchAction({ query: 'test' });
}
componentWillUnmount() {
// Deregister listener on unmount to clean up memory references
this.props.ctx.customPortlets.removeEventListener(SearchResultsEventName, this.onSearchResults);
}
onSearchResults(success, data) {
if (!success) {
this.setState({ isLoading: false, hasError: true });
return;
}
this.setState({ isLoading: false, results: data.items });
}
render() {
if (this.state.isLoading) {
return <div>Loading...</div>;
}
if (this.state.hasError) {
return <div>An error occurred while loading search results.</div>;
}
return <div>{`There were ${this.state.results.length} search results found.`}</div>;
}
}
replaceView(<TFC_SweetSearchResults ctx={ctx} />);
Comments
0 comments
Please sign in to leave a comment.