Skip to main content
Version: 13.x (Current)

Button

<bk-button></bk-button>

The Button component renders a generic button that can be configured to execute some action upon clicking.

How to configure

The behavior upon clicking is defined by property action, which can be configured to perform the following tasks, or a combination of them:

  • push events into the event-bus
  • perform HTTP requests
  • redirect to another page
  • upload / download files
  • copy data into clipboard

Property action can be configured following the Back-kit Action interface.

Action

The action property allows to configure a Back-kit Action that should be implemented by the rendered button upon clicking.

Each action in the component is executed with the following context:

{
pathnameParams: ..., // parameters extracted from pathname part of URL. Requires `urlMask` property to be specified.
searchParams: ..., // parameters extracted from search part of URL. Requires `urlMask` property to be specified.
currentUser: ..., // data relative to the current user.
selectedData: ..., // currently selected data. Requires `bulkButton` property to be true.
selectedParents: ..., // history of parents through which the user has navigated to get to the current view
context: ... // extra context set by mounting component
}

which allows for dynamic configurations through handlebars syntax.

{
"tag": "bk-button",
"properties": {
"content": "Register to race",
"action": {
"type": "http",
"config": {
"url": "/race",
"method": "POST",
"body": {
"id": "{{currentUser.id}}",
"nickname": "{{currentUser.nickname}}"
}
}
}
}
}

Context

Dynamic configuration is possible when defining how the button should react to being clicked. Namely, the entry of the action property are parsed with handlebars before being converted into callbacks, with the following properties injected as context:

  • currentUser, contains information about the current user, for example name and email.

  • pathnameParams, contains information about the pathname of the current URL. This is only available upon correctly configuring a value for property urlMask.\ pathnameParams.params includes the result of the match between the urlMask property and the pathname of the URL, while pathnameParams.path holds the full pathname.\ It contains the property params with the keys specified in the urlMask and the property path with the full query parameters string.

    {
    "params": {
    "id": "order-id-1"
    },
    "path": "/order-details/order-id-1"
    }
  • searchParams contains information about the URL query parameters. This is only available upon correctly configuring a value for property urlMask.\ searchParams.params includes the result of the match between the urlMask property and the query of the URL, while searchParams.path holds the full query as a string.\ It contains the property params with the keys specified in the urlMask and the property path with the full query parameters string.

    {
    "params": {
    "sort": "ascending",
    "color": "red"
    },
    "path": "?sort=ascending&color=red"
    }
  • selectedData, contains an array of objects representation of the selected data. Requires the property bulkButton to be true, operating the button to operate in bulk mode. Selected data is then accessible in dynamic configuration through key selectedData.

    {
    selectedData: [
    {
    "name": "Sara",
    "dateOfBirth": {
    "day": "30",
    "month": "May",
    "year": "1994"
    }
    },
    {
    "name": "Dave",
    "dateOfBirth": {
    "day": "21",
    "month": "September",
    "year": "1956"
    }
    }
    ]
    }

    Most of the times, selectedData is used in conjunction with rawObject helper, like {{rawObject selectedData}}, which signals to the Button that the selected data should not stringified but rather kept as array. For instance, to inject the selected data items into the body of a POST call, {{rawObject selectedData}} should be used.

  • selectedParents, contains an array with all the nesting layers which were navigated.

  • extra context. The Button supports extra context, which could be set by the user using context property, or, most of the times, by a parent component that mounts the Button. For instance, the Table component renders a table that may include instances of the Button component as action buttons. The Table provides the mounted Buttons with an object representation of the corresponding row, which can then be used in action configuration via keywork args.[1].

Require Confirmation

It is possible to ask for confirmation before executing an action emitting a require-confirm event, and nesting the desired action in the payload of the event. This approach requires a component such as the Confirmation Modal to be included in the plugin.

{
"tag": "bk-button",
"properties": {
"action": {
"type": "event",
"config": {
"events": {
"label": "require-confirm", // -> this opens the confirmation dialog-box
"payload": {
"configOk": { // -> this is the OK button of the confirmation dialog-box
"tag": "bk-button",
"properties": {
"content": "Confirm",
"action": {
... // -> action to be executed, for which a confirmation should be requested
}
}
}
}
}
}
}
}
}
danger

When wrapping the action inside a require-confirm event in this way properties loadingOnAction and disableOnAction should not be set to true, as the button will enter loading / disabled status without ever leaving it.

Bulk button

It is possible to create a button that keeps in state selected items by setting bulkButton property to true. By setting bulkButton property to true, the Button keeps an internal representation of items selected through components such as the Table. Selected data can then be referenced in actions using selectedData. Most of the times, selectedData should be used in configurations with rawObject helper keyword, {{rawObject selectedData}}. rawObject prevents the referenced data from being stringified during the dynamic value resolution step.

{
"tag": "bk-button",
"properties": {
"content": "Register to List",
"bulkButton": true,
"action": {
"type": "http",
"config": {
"url": "/v2/users/",
"method": "POST",
"body": "{{rawObject selectedData}}"
}
}
}
}

Loading / disable on action

Properties loadingOnAction and disableOnAction put the button in loading/disabled state when an action of type event, http, file-upload is executed. The button exits loading/disabled status once any result event is received about the outcome of the action. Result events are: success, error, cancel.

{
"tag": "bk-button",
"properties": {
"loadingOnAction": true,
"action": {
"type": "http",
"config": {
"url": "/orders-count",
"method": "GET"
}
}
}
}

For actions of type http and file-upload, result events are emitted by the Button itself. This virtually ensures that the Button exists loading/disabled state, provided a response is received. However, for actions of type event, result events are not emitted by the Button itself, but rather rely on other components to do so - typically client components, like the Crud Client. Generally, clients emit result events after performing HTTP requests.

Consequently, in order to avoid entering loading/disabled status without ever leaving it, a Button that emits events should only use loadingOnAction or disableOnAction if a following result event is eventually triggered - that is, if the button sends events that trigger an HTTP call from clients. For instance, create-data, update-data, delete-data eventually trigger the CRUD client to emit result events, allowing the Button to exit loading/disabled state.

Examples

Example: Basic Usage

The Button can be configured to execute multiple types of Back-kit Actions, and combine them.

Example of a Button that executes as HTTP call:

{
"tag": "bk-button",
"properties": {
"content": "Count Orders",
"loadingOnAction": true,
"action": {
"type": "http",
"config": {
"url": "/orders-count",
"method": "GET"
}
}
}
}

Example of a Button that notifies the need for item creation via event:

{
"tag": "bk-button",
"properties": {
"content": "Create New Item",
"action": {
"type": "event",
"config": {
"events": {
"label": "add-new",
"payload": {}
}
}
}
}
}

Example of a Button that navigates to a given href:

{
"tag": "bk-button",
"properties": {
"content": "Go To Customers",
"action": {
"type": "href",
"config": {
"href": "/cutomers-list"
}
}
}
}

Example of a Button that performs an HTTP call and, in case of successful response, navigates to a given href:

{
"tag": "bk-button",
"properties": {
"content": "Count orders and go to customers",
"action": {
"type": "http",
"config": {
"url": "/orders-count",
"method": "GET"
}
},
"hooks": {
"onSuccess": {
"type": "href",
"config": {
"href": "/cutomers-list"
}
}
}
}
}

Example: Use Data from URL

The Button component can use urlMask property to extract information from the current page URL, and inject it as context when resolving dynamic references from its action configuration.

{
"tag": "bk-button",
"properties": {
"content": "Add to chart",
"urlMask": "/order-details/:id",
"action": {
"type": "http",
"config": {
"url": "/chart",
"method": "POST",
"body": {
"id": "{{pathnameParams.params.id}}"
}
}
}
}
}

The resulting component is a button that, on click, performs a POST request to "/chart", with body containing information extracted from the current page URL and from the information of the currently logged user. Assuming the URL to be "/order-details/order-id-1", then body of the POST request will be:

{
"id": "order-details-1"
}

Pathname vs Query

It is also possible to specify different masks for pathname and query portions of the URL.

{
"tag": "bk-button",
"properties": {
"content": "Add To Chart",
"urlMask": {
"pathname": "order-details/:id",
"search": "\\?color=:myColor"
},
"action": {
"type": "http",
"config": {
"url": "/chart",
"payload": {
"orderId": "{{pathnameParams.params.id}}",
"color": "{{searchParams.params.myColor}}"
}
}
}
}
}

Assuming the URL to be "/order-details/order-id-1?color=red", then body of the POST request will be:

{
"orderId": "order-details-1",
"color": "red"
}

Example: Inside Table

One common use case of the Button component is to be used as action buttons inside other components, such as the Table component. The Table renders all action buttons in every rows of the table, and injects the object representation of the corresponding row as extra context for the Button, retrievable via the args.[1] keyword, which can be used when configuring the action via handlebars.

{
"args.[1]": {...}, // Corresponding row of the table
"args.[2]": ..., // Index of the row of the table
}

The following configuration renders a Button component which, on click, notifies the need to visualize / allow editing of the details of the corresponding row. Technically: emits a selected-data event with the corresponding table row as payload.

{
"tag": "bk-button",
"properties": {
"content": "Edit",
"action": {
"type": "event",
"config": {
"events": {
"label": "selected-data",
"payload": "{{rawObject args.[1]}}"
}
}
}
}
}
info

rawObject is a helper keyword that prevents selected items from being stringified in the payload of the event.

The following button downloads a file from an endpoint that depends on the value of the imageUrl field of the corresponding table row:

{
"tag": "bk-button",
"properties": {
"content": "Download Image",
"action": {
"type": "file-download",
"config": {
"url": "/files/{{rawObject args.[1].imageUrl}}"
}
}
}
}

Example: Nested objects

The Button provides context to retrieve information on the navigated nested objects through keywork selectedParents, which can thus be used within handlebars to configure the Button action.

Assuming a collection with three levels of nesting is being displayed in a component that allows navigating nesting objects (like the Table component)

companies
- employees
- projects
{
"companies": {
"type": "array",
"items": {
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"employees": {
"type": "array",
"items": {
"type": "object",
"properties": {
"_id": {
"type": "string"
},
"projects": {
"type": "array",
"items": {
"type": "object",
"properties": {
"title": {"type": "string"},
"description": {"type": "string"}
}
}
}
}
}
}
}
}
}
}

When navigating to the third nesting level (entering "projects"), selectedParents holds information about both the parent company and the parent employee.

{
"selectedParents.[0]": {...}, // selected company
"selectedParents.[1]": {...}, // selected employee
}

When at the "employees" nesting level, a Button for removing an employee from a company could be configured as:

{
"tag": "bk-button",
"properties": {
"content": "Remove from Company",
"action": {
"type": "http",
"config": {
"method": "DELETE",
"url": "/v2/companies/{{selectedParents.[0]._id}}/employees/{args.[1]._id}"
}
}
}
}

selectedParents.[0]._id is the _id field of company that was selected in the first nesting step, while args.[1]._id is how to access the "_id" field of a row in the Table component.

Example: Require confirmation

The following button allows the user to upload a file to "/files" endpoint.

{
"tag": "bk-button",
"properties": {
"content": "Confirm",
"action": {
"type": "file-upload",
"config": {
"url": "/files"
}
}
}
}

to require confirmation for this action, it should be wrapped in the payload of event require-confirm:

{
"tag": "bk-button",
"properties": {
"content": "Upload File",
"action": {
"type": "event",
"config": {
"events": {
"label": "require-confirm", // -> this opens the confirmation dialog-box
"payload": {
"content": "Are you sure you want to upload a new file?", // -> this is the message displayed by the dialog-box
"configOk": { // -> this is the OK button of the confirmation dialog-box: the "main action" delegated to this button
"tag": "bk-button",
"properties": {
"content": "Confirm",
"action": {
"type": "file-upload",
"config": {
"url": "/files"
}
}
}
}
}
}
}
}
}
}

If a component such as the Confirmation Modal is included in the plugin, it will react to the require-confirm event emitted by the button on click, using the configOk key in the payload to determine what action should be executed upon confirmation.

Example: Bulk operations

When items are selected in components such as the Table or the Gallery, a Button with bulkButton property set to true will provide access to selected items in its configuration through the selectedData keywork.

{
"tag": "bk-button",
"properties": {
"content": "Register to List",
"bulkButton": true,
"action": {
"type": "http",
"config": {
"url": "/v2/users/",
"method": "POST",
"body": "{{rawObject selectedData}}",
}
}
}
}
info

rawObject is a helper keyword that prevents selected items from being stringified in the body of the request.

Example: Deselect items after action

When items are selected in components such as the Table or the Gallery, executing a bulk action from the Button might not trigger items de-selection. It is possible to deselect them by piping a change-query event with an empty payload after the main action, using actions hooks.

{
"tag": "bk-button",
"properties": {
"content": "Register to List",
"bulkButton": true,
"action": {
"type": "http",
"config": {
"url": "/v2/users/",
"method": "POST",
"body": "{{rawObject selectedData}}",
},
"hooks": {
"onFinish": {
"type": "event",
"config": {
"events": {
"label": "change-query",
"payload": {}
}
}
}
}
}
}
}

Example: Enter loading/disabled state during action

{
"tag": "bk-button",
"properties": {
"loadingOnAction": true,
"action": {
"type": "http",
"config": {
"url": "/orders-count",
"method": "GET"
}
}
}
}

Upon clicking the rendered button:

  1. the Burron enters loading state
  2. the Burron performs the http POST request
  3. the Burron emits a success or error event, depending on the result of the call
  4. the Burron dismisses loading state after listening to the result event emitted by itself in the previous step

Example: Loading with action chaining

A Button can be configured to execute multiple using action hooks. The following example shows a Button that chains two actions on click:

  • sends an GET request to "/order-metadata"
  • then, once a response is received, emits a create-data event.

Properties loadingOnAction and disableOnAction cause the Button to enter loading/disabled state once for each chained action of type events, http, file-upload.

{
{
"tag": "bk-button",
"properties": {
"content": "Count orders and create data",
"loadingOnAction": true,
"action": {
"type": "http",
"config": {
"url": "/order-metadata",
"method": "GET"
},
"hooks": {
"onFinish": {
"type": "event",
"config": {
"events": {
"label": "create-data",
"payload": {
"name": "New Order",
"price": 150
}
}
}
}
}
}
}
}
}

with such configuration, if the CRUD Client component is included in the plugin, the Button enters loading state twice when clicked, once for each chained action. The full flow can be broken down as follows. Upon clicking:

  1. the Button enters loading state
  2. the Button performs the http POST request
  3. the Button emits a success or error event, depending on the result of the call
  4. the Button dismisses loading state after listening to the result event emitted by itself on step 3
  5. the Button emits an event with label create-data and specified payload, and parallely newly enters loading state
  6. the CRUD Client listens to the create-data event, which triggers its own flow to create a new item
  7. the CRUD Client emits a success or error event depending on the result of the item creation
  8. the Button dismisses loading state after listening to the event emitted by the CRUD Client on step 8

The Button thus enters and dismisses loading state twice.

Please note that, in the case of actions of type http, the button itself emits a result event (step 3). As a consequence, the button's loading state will be appropriately terminated once a response is received. On the contrary, actions of type event prompt a result event to be emitted from a distinct component (step 7). This implies that the button's successful exit from the loading state hinges on the reactions of other components to the event that is emitted. Therefore, when configuring the button's action, extra caution should be exercised.

API

Properties & Attributes

propertyattributetypedefaultdescription
content-LocalizedText{}button content
dangerdangerboolean-danger flag
disableOnActiondisable-on-actionbooleanfalseconfigures the button to be disabled while action is in progress
disableddisabledbooleanfalsebutton disabled property
iconIdicon-idstring-defines which icon should be rendered into the button, if this property is not defined or doesn't match any icon no icon will be rendered
iconPlacement-"default" | "left" | "right""default"defines where icon should be rendered, either left or right defaulting on left
listenToLoadingDatalisten-to-loading-databooleanfalseconfigures the button to be loading when trigger by a loading-data event
loadingloadingbooleanfalsebutton loading property
loadingDebounceloading-debouncenumber400min time in milliseconds between loading swaps (when less it doesn't trigger loading rendering)
loadingOnActionloading-on-actionbooleanfalseconfigures the button to be loading while action is in progress
navigationStrategy-"disable" | "hide"-determines the button behavior upon navigating nested objects. Allowed values are 'disable' and 'hide'. By default, the button does not react to navigation events.
shapeshapestring'round'button shape property
typetypestring'primary'button type property
urlMaskurl-maskUrlMask''url mask to apply to the current path to extract dynamic parameters
action-Action-schema describing How to configure onClick event
bulkButton-booleanfalsewhether to use it as a bulk button or not. If set to true, it listens to selected-data-bulk event

Listens to

eventdescription
loading-dataenters loading state if property listenToLoadingData is set to true
selected-data-bulkkeeps track of user selections if property bulkButton is set to true
nested-navigation-state/backkeeps track of navigation steps
nested-navigation-state/pushkeeps track of navigation steps

Emits

eventdescription
configurable eventgeneric event configurable through the event type configuration
errorcontains error messages for an http event
successnotifies a successful http request