Consumer API
The Consumer
is a higher-order function that can be used to “Decorate” PageBuilder Engine components and provide them with useful Props and Instance Methods via React’s Context API. The Consumer
function can wrap any component type, although it is most typically used for Features. It can be used for both class-based components and functional components to provide props
, however functional components will be unable to use the Instance Methods provided by Consumer
.
Implementation
The Consumer
function is imported from the fusion:consumer
namespace. It can be invoked as a function or using decorator syntax; both produce the same result.
Example
Decorator Syntax
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass MyComponent extends Component { ...}
export default MyComponent
Function Syntax
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
class MyComponent extends Component { ...}
export default Consumer(MyComponent)
Props
Consumer
components will be provided with all Context Props, along with the following:
editableContent() (Function)
Description
A function that adds the necessary attributes to make the element’s content “editable”. Use this method to allow PageBuilder editors to change individual ANS content nodes before rendering. This function can be run on a single content node, or on multiple labeled content nodes.
Parameters
Single Node Syntax
editableContent(contentObj, contentKeyPath)
contentObj
(ANS Object): The root ANS content object that thecontentKeyPath
should pull from.contentKeyPath
(String): The ‘key path’ within the ANS object to find the content node that should be editable.
Multi-Node Syntax
editableContent(contentObj, contentNodeMap)
-
contentObj
(ANS Object): The root ANS content object that thecontentKeyPath
should pull from. -
contentNodeMap
(Object): A map of labels (acting as keys) to their correspondingcontentKeyPath
values.contentNodeMap.{contentLabel}
(String): Here,{contentLabel}
represents the name of the property this content node represents. This label will be capitalized and displayed to an editor in the UI. The value of the key is acontentKeyPath
string, as in the “single node” syntax above.
Return
This function returns 3 attributes to be added to the target element. PageBuilder Engine uses these attributes to identify the element and apply the content edits.
contentEditable
: An HTML attribute denoting that this element is editable in the browser.data-content-editable
: An attribute representing the ID of the piece of content and property to be mapped in the ANS document.data-feature
: Returns the Feature ID of the feature this method is added to.
Example
Single Node Content Editable
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass EditableHeadline extends Component { ... render() { // This `content` would come from a content fetch performed elsewhere in this component const { content } = this.state
return ( <h1 {...this.props.editableContent(content, 'headlines.basic')}> {content.headlines.basic} </h1> ) }}
export default EditableHeadline
Multi-Node Content Editables
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass EditableHeadline extends Component { ... render() { // This `content` would come from a content fetch performed elsewhere in this component const { content } = this.state
return ( <> <h1 {...this.props.editableContent(content, { headline: 'headlines.basic', subheadlines: 'subheadlines.basic', description: 'description.basic', })} > {content && content.headlines ? content.headlines.basic : ''} </h1> <h3> {content && content.subheadlines ? content.subheadlines.basic : ''} </h3> <p> {content && content.description ? content.description.basic : ''} </p> </> ) }}
export default EditableHeadline
searchableContent() (Function)
Description
A function that adds the necessary attributes to enable search integrations in PageBuilder Editor. Use this method to allow PageBuilder editors to replace content source values using the built-in content search tools.
searchableContent() will generate multiple data attributes. Also, the parent container must include a style of position: relative
for proper button placement in the Editor UI.
Parameters
searchableContent(contentObj, customFieldMap)
-
contentObj
(ANS Object): The root ANS content object thatcustomFieldMap.{contentSourcePath}
should pull from. -
customFieldMap
(Object): A map of custom fields to their correspondingcontentKeyPath
values.customFieldMap.{contentSourcePath}
(String): Here,{contentSourcePath}
represents the key path in the content source that will be overridden with the searched content. The value in this map is the content key path in the searched content response.
Return
This function returns 4 attributes to be added to the target element. PageBuilder Engine uses these attributes to identify the element and apply the content edits.
contentEditable
: An HTML attribute denoting that this element is editable in the browser.data-content-editable
: An attribute representing the ID of the piece of content and property to be mapped in the ANS document.data-feature
: Returns the Feature ID of the feature this method is added to.data-searchable
: An HTML attribute denoting that this element is searchable in the browser.
Example
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass SearchableImage extends Component { ... render() { // This `content` would come from a content fetch performed elsewhere in this component const { content } = this.state const { customFields, searchableContent } = this.props
// This example replaces two custom fields (imageOverrideUrl and imageOverrideAltText) with content from the Photo Center API return ( <div style={{ position: 'relative' }}> <img src={customFields.imageOverrideUrl || content.promo_items.basic.url} alt={customFields.imageOverrideAltText || content.promo_items.basic.subtitle} {...searchableContent(content, { 'promo_items.basic.url': 'additional_properties.resizeUrl', 'promo_items.basic.subtitle': 'subtitle' })} /> </div> ) }}
export default SearchableImage
searchableField() (Function)
Description
A function that adds the necessary attributes to enable search integrations in PageBuilder Editor. Use this method to allow PageBuilder editors to replace a Custom Field using the built-in content search tools.
searchableField()
will generate multiple data attributes. Also, the parent container must include a style of position: relative
for proper button placement in the Editor UI.
Parameters
Single-Field Syntax
searchableField(customFieldKey)
customFieldKey
(String): The custom field that will be replaced with the value provided by the selected content.
Multi-Field Syntax
searchableField(customFieldMap)
-
customFieldMap
(Object): A map of custom fields to their correspondingcontentKeyPath
values.customFieldMap.{customFieldKey}
(String): Here,{customFieldKey}
represents the custom field that will be overridden with the searched content. The value in this map is the content key path within the searched content response.contentIntegrationType
(String): The type of content integration to associate with thecontentConfig
optionsParameter
(Object): An object which at this time, only takes a contentSource prop. The value should be the name of the content source- Example:
{ contentSource: 'story-search' }
- Example:
Return
This function returns 4 attributes to be added to the target element. PageBuilder Engine uses these attributes to identify the element and apply the content edits.
contentEditable
: An HTML attribute denoting that this element is editable in the browser.data-field-editable
: An attribute representing the custom field to be overriddendata-feature
: Returns the Feature ID of the feature this method is added to.data-searchable
: An HTML attribute denoting that this element is searchable in the browser.data-content-source
: An attribute for setting the content source to use for the block.
Example
Single-Field Example
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass SearchableImage extends Component { ... render() { // This `content` would come from a content fetch performed elsewhere in this component const { content } = this.state const { customFields, searchableField } = this.props
// This example replaces the imageOverrideUrl custom field with the default image URL provided by the Photo Center API return ( <div style={{ position: 'relative' }}> <img src={customFields.imageOverrideUrl || content.promo_items.basic.url} {...searchableField('imageOverrideUrl' 'story', {content-Source: 'story-search' })} /> </div> ) }}
export default SearchableImage
Multi-Field Example
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass SearchableImage extends Component { ... render() { // This `content` would come from a content fetch performed elsewhere in this component const { content } = this.state const { customFields, searchableField } = this.props
// This example replaces two custom fields (imageOverrideUrl and imageOverrideAltText) with content from the Photo Center API return ( <img src={customFields.imageOverrideUrl || content.promo_items.basic.url} alt={customFields.imageOverrideAltText || content.promo_items.basic.subtitle} {...searchableField({ 'imageOverrideUrl': 'additional_properties.resizeUrl', 'imageOverrideAltText': 'subtitle' }, 'story', { contentSource: 'story-search'
})} /> ) }}
export default SearchableImage
Instance Methods
addEventListener() - (Function)
Description
This method adds an event listener to a PageBuilder Engine component that will respond to events of the specified eventName
by invoking the specified eventHandler
. Events are dispatched by invoking DispatchEvent in other PageBuilder Engine components. Listeners can be removed by the RemoveEventListener method.
Parameters
addEventListener(eventName, eventHandler)
eventName
(String): The name of the event to subscribe to.eventHandler(payload)
(Function): The function that will handle the event when it is triggered. This function receives the event’s payload as its only argument.
Return
This method returns undefined
; its effect is to ‘subscribe’ the event handler to the appropriate event.
Example
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass ErrorMessage extends Component { ... componentDidMount () { this.addEventListener('errorOccurred', (error) => { const errorMsg = error && error.message ? error.message : 'Something went wrong' this.setState({ message: errorMsg }) }) } ...}
export default ErrorMessage
dispatchEvent() - (Function)
Description
This method dispatches an event from a PageBuilder Engine component of the specified eventName
with an arbitrary payload
to be received by another component’s event handling function (which gets subscribed via the AddEventListener method).
Parameters
dispatchEvent(eventName, payload)
eventName
(String): The name of the event to dispatch, which listeners can subscribe to.- [
payload
] (?): An arbitrary payload attached to the event, for the handler to use in processing.
Return
This method returns undefined
; its effect is to dispatch the event to each subscriber.
Example
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass WeatherLookup extends Component { ... handleFormInput(value) { if (!value || value.length < 5) { this.dispatchEvent('errorOccurred', { val: value, message: 'Zip code must be at least 5 characters long.' }) } ... } ...}
export default WeatherLookup
fetchContent() - (Function)
Description
The fetchContent
method is second-level syntactic sugar for using both GetContent and React’s setState
together. It takes a map whose keys are the names of content to be stored in the component’s state
(using setState
), and the values are configuration options used to fetch content from a content source (using getContent
). fetchContent
will then fetch the content using the content configuration and set it on the component’s state
using the key names in contentConfigMap
.
Parameters
fetchContent(contentConfigMap)
-
contentConfigMap
(Object): An object whose keys are the names of content to be stored in the component’sstate
, and the values are configuration objects identical to those of the GetContent parameters. -
contentConfigMap.{contentKey}
(Object): Here,{contentKey}
represents the name of a property the developer chooses to set on the component’sstate
object. Multiple{contentKey}
objects can exist on the samecontentConfigMap
object.contentConfigMap.{contentKey}.source
(String): Seesource
parameter in GetContent method.contentConfigMap.{contentKey}.query
(Object): Seequery
parameter in GetContent method.- [
contentConfigMap.{contentKey}.inherit
] (Boolean): Seeinherit
parameter in GetContent method. - [
contentConfigMap.{contentKey}.staticMode
] (Boolean): SeestaticMode
parameter in GetContent method.
Return
This method returns undefined
; its effect is to set the state
properties listed in the contentConfigMap
with the appropriate values.
Example
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass Topics extends React.Component { constructor (props) { super(props)
this.fetchContent({ topics: { source: 'content-feed', query: { feedType: 'taxonomy.tags.slug', feedParam: '*', limit: 5, offset: 0, order: 'display_date:desc' }, filter: '{ headline }' } }) }
render () { return ( <ul> {this.state.topics.map(topic => <li>{topic.headline}</li> )} </ul> ) }}
export default Topics
getContent() - (Function)
Description
The getContent
method will fetch content, both on the server and the client, from a content source (identified by the sourceName
argument) defined in the bundle.
Parameters
For syntactic sugar, there are 2 ways to invoke the getContent
method: with the arguments expanded and passed individually, or as keys of an object.
Expanded Syntax
getContent(sourceName, query, [filter], [inherit])
sourceName
(String): The name of the content source from which you want to fetch. This content source must be configured in your bundle.query
(Object): This will depend on the definition of the content source, but will be an object containing key/value pairs used to uniquely identify the piece of content you want to fetch.- [
filter
] (String): A GraphQL query string that will be applied to the resultant data to minimize the payload size. This is beneficial for both client-side and server-side fetching, as server-side fetched data must be included in the final HTML rendering to prevent content flashing. See The Content Filtering Guide For More Details. - [
inherit
] (Boolean): A dynamic boolean to determine ifglobalContent
should be used to override the config settings provided. If this value istrue
, theglobalContent
will be returned in both thecached
property and as the resolution offetched
. - [
staticMode
] (Boolean): A flag to indicate that the content fetched for this will only be used within Static components and that there is no logic that requires that data on the client. This option prevents the content fetched from being passed to the client for when the app gets hydrated client-side. It also prevents this content fetch from happening client-side. This means that a content fetch using this flag will always return nothing when run in a browser.
Object Syntax
getContent(options)
-
options
(Object): An object containing the following properties:options.sourceName
(String): SeesourceName
parameter above.options.query
(Object): Seequery
parameter above.- [
options.filter
] (String): Seefilter
parameter above. - [
options.inherit
] (Boolean): Seeinherit
parameter above. - [
options.staticMode
] (Boolean): SeestaticMode
parameter above.
Return
An object with 2 keys: { cached, fetched }
. cached
will be an object containing data already pre-fetched synchronously on the server from the content source. fetched
will be a Promise that resolves to an object containing newly fetched data from the content source.
Example
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass WeatherForecast extends Component {
constructor() { super(props) this.state = { forecast: null } }
componentDidMount () { navigator.geolocation.getCurrentPosition((location) => { // If we get the user's location, call getContent to fetch data from the DarkSky API const { fetched } = this.getContent({ // Specifying the `dark-sky` content source sourceName: 'dark-sky', // `query` object needs `lat` and `lng` arguments to query the DarkSky API query: { lat: location.coords.latitude, lng: location.coords.longitude }, // GraphQL filter so we get only the data we need filter: '{ daily { summary }}' })
// Use the `fetched` Promise to get our response and set the forecast info in the component's state fetched.then(response => { this.setState({ forecast: response.daily.summary }) }) }) }
render() { const { forecast } = this.state return forecast ? (<p>{forecast}</p>) : null }}
export default WeatherForecast
removeEventListener() - (Function)
Description
This method ‘unsubscribes’ the specified event handling function (eventHandler
) from the eventName
specified. The eventHandler
must be a reference to the exact function instance that was added via AddEventListener, not a copy.
Parameters
removeEventListener(eventName, eventHandler)
eventName
(String): The name of the event to unsubscribe the handler from.eventHandler
(Function): A reference to the exact instance of the handler function that was previously added.
Return
This method returns undefined
; its effect is to ‘unsubscribe’ the event handler from the appropriate event.
Example
import Consumer from 'fusion:consumer'import React, { Component } from 'react'
@Consumerclass ErrorMessage extends Component { handleErrorMsg (error) { const errorMsg = error && error.message ? error.message : 'Something went wrong' this.setState({ message: errorMsg }) }) }
componentDidMount () { this.addEventListener('errorOccurred', this.handleErrorMsg.bind(this)) }
componentWillUnmount () { this.removeEventListener('errorOccurred', this.handleErrorMsg) } ...}
export default ErrorMessage