Lightning Components для работы с Flows Flows ( FlowButton)

Хотелось бы поделиться с участниками форума компонентами, которые немного разнообразили бы работу с Flow. А именно отображение Buttons и еще таким полезным компонентом как RecordTabCloser, который можно помещать не только в Flow, но и на обычных PageLayouts.

Наверное стоит начать с того, для чего нужен именно этот компонент под названием FlowButton.

Например стоит задача:

  1. Отобразить кнопку не стандартных размеров или вообще отобразить ее на всю ширину
    скрина.
  2. Отобразить кнопку не стандартных цветов (но в цветах salesforce), например “destructive (красный цвет) или inverse”.
  3. Отобразить кнопку с какой нибудь Icon, скажем кнопка с корзиной или любым другим icon
    от Salesforce
  4. Cкрыть кнопку или сделать ее не активной
  5. Расположить кнопку по центру, слева, справа.
  6. Выдавать сообщение в сплывающем окне при нажатии на кнопку

Ну и уже смотря на пример, можно расширять этот компонент как душе угодно.

1) FlowButton.cmp

<aura:component description="FlowButton" implements="lightning:availableForFlowScreens">
    <aura:attribute name="active" type="Boolean" default="true"/>
    <aura:attribute name="availableActions" type="String[]"/>
    <aura:attribute name="buttonPressed" type="Boolean" access="public" />
    <aura:attribute name="disabled" type="Boolean" default="false"/>
    <aura:attribute name="previous" type="Boolean" default="false"/>
    <aura:attribute name="show" type="Boolean" default="true"/>

    <aura:attribute name="align" type="String" access="public"/>
    <aura:attribute name="buttonLabel"  type="String" access="public" required="true" />
    <aura:attribute name="buttonVariant"  type="String" access="public" default="neutral" />
    <aura:attribute name="buttonWidth" type="String"/>
    <aura:attribute name="confirmMessage" type="String" access="public"/>
    <aura:attribute name="confirmHeaderText" type="String" access="public" default="Confirm Action"/>
    <aura:attribute name="helptext" type="String" access="public"/>
    <aura:attribute name="iconName" type="String" access="public"/>

    <aura:attribute name="width" type="String" access="private"/>

    <lightning:overlayLibrary aura:id="overlayLib"/>
    <aura:registerEvent name="navigateFlowEvent" type="c:navigateFlow"/>
    <aura:handler value="{!this}" action="{!c.doInit}" name="init"/>

    <aura:if isTrue="{!v.show}">
        <div class="{! 'slds-text-align--' + v.align + ' slds-clearfix slds-p-top--medium' }">
            <lightning:button disabled="{!v.disable}" class="{!v.width + ' slds-button slds-button_'+v.buttonVariant+' slds-button_'+v.buttonType}"
                              onclick="{!c.handleClick}" label="{!v.buttonLabel}" variant="{!v.buttonVariant}">
                <aura:set attribute="iconName" value="{!v.iconName}"/>
            </lightning:button>
            <aura:if isTrue="{!not(empty(v.helptext))}">
                <lightning:helptext
                    content="{!v.helptext}"/>
            </aura:if>
        </div>
    </aura:if>
</aura:component>
  1. FlowButton.design
<design:component>
    <design:attribute name="active" label="Action: Active" description="True or False to active or deactive the button"/>
    <design:attribute name="buttonLabel"  label="Label" default="true"/>
    <design:attribute name="confirmHeaderText" label="Action: ConfirmHeader"/>
    <design:attribute name="confirmMessage" label="Action: ConfirmMessage"/>
    <design:attribute name="helptext" label="Action: Helptext"/>
    <design:attribute name="previous" label="Action: Previous" description="True or False to mark the button as a previous button"/>
    <design:attribute name="show" label="Action: Show" description="True or False to show or hide the button"/>

    <design:attribute name="align" label="Design: Align" dataSource="left,right,center" description="Align: left, right, center"/>
    <design:attribute name="buttonVariant" label="Design: Variant" dataSource="neutral,success,base,destructive,inverse,brand"
    description="Variant: neutral, success, base, destructive, inverse, brand"/>
    <design:attribute name="buttonWidth" label="Design: ButtonWidth" description="Width: xxx-small, xx-small, x-small, medium, x-large, full"/>
    <design:attribute name="iconName"  label="Design: Icon"/>
    <design:attribute name="buttonPressed" label="Variable (output)"/>
</design:component>
  1. FlowButtonController.js
({
    doInit: function (component, event, helper) {
        /**
         * set the active button
         */
        var active = component.get('v.active');

        if (active === true) {
            component.find('v.disabled', false);
        } else {
            component.set('v.disabled', true);
        }

        /**
         * set the width of button full(stretch) or e.g x-large,large,medium
         */
        var buttonWidth = component.get('v.buttonWidth');

        if (buttonWidth === 'full') {
            component.set('v.width', 'slds-button_stretch');
        } else {
            component.set('v.width', 'slds-size_' + buttonWidth);
        }
    },
    handleClick: function (component, event, helper) {

        const confirmMessage = component.get("v.confirmMessage");

        if (!!confirmMessage) {
            $A.createComponents([
                ["c:FlowButtonConfirm", {messageRichtext: confirmMessage}],
                ["c:FlowButtonConfirmButtonBar", {}]
            ], $A.getCallback(function (newComponents, status) {
                if (status === 'SUCCESS') {
                    const textComponent = newComponents[0];
                    const buttonBarComponent = newComponents[1];
                    buttonBarComponent.addEventHandler("confirmEvent", component.getReference("c.handleConfirm"));

                    component
                        .find("overlayLib")
                        .showCustomModal({
                            header: component.get("v.confirmHeaderText"),
                            body: textComponent,
                            footer: buttonBarComponent,
                            showCloseButton: false
                        })
                } else {
                    console.error(arguments);
                }
            }))
        } else {
            component.set("v.buttonPressed", true);

            var availableActions = component.get("v.availableActions");

            if (component.get("v.previous")) {
                helper.setNextOrFinish(component, "BACK");
            }

            if (availableActions.includes("NEXT")) {
                helper.setNextOrFinish(component, "NEXT");
            } else {
                helper.setNextOrFinish(component, "FINISH");
            }
        }
    },
    handleConfirm: function (component, event, helper) {

        component.set("v.buttonPressed", true);

        const availableActions = component.get("v.availableActions");

        if (availableActions.includes("NEXT")) {
            helper.setNextOrFinish(component, "NEXT");
        } else {
            helper.setNextOrFinish(component, "FINISH");
        }
    }
})
  1. FlowButtonHelper.js
({
    /**
     function to set the status of the next screen (finish or next)
     @param component,param
     */
    setNextOrFinish: function (component, param) {

        var navigate = component.get("v.navigateFlow");

        if (navigate) {
            navigate(param);
        } else {
            navigate = component.getEvent("navigateFlowEvent");
            navigate.setParam("action", param);
            navigate.fire();
        }
    }
})

Так же для отображения всплывающего окна при нажатии на кнопку, нам понадобятся другие два Компонента.

  1. FlowButtonConfirm.cmp

<aura:component description="FlowButtonConfirm">
  <aura:attribute type="String" name="messageRichtext" required="true" />
  <ui:outputRichText value="{!v.messageRichtext}" />
</aura:component>

и другой компонент

  1. FlowButtonConfirmButtonBar.cmp
<aura:component>
  <aura:attribute access="public" type="Boolean" name="isConfirm" default="false" />

  <aura:registerEvent name="confirmEvent" type="c:FlowButtonConfirmButtonBarConfirm" />

  <lightning:overlayLibrary aura:id="overlayLib"/>
  <lightning:button name="cancel" label="Cancel" onclick="{!c.handleCancel}"/>
  <lightning:button name="ok" label="OK" variant="brand" onclick="{!c.handleOK}"/>
</aura:component>

FlowButtonConfirmButtonBarController.js

({
  handleCancel : function(component, event, helper) {
    component.find("overlayLib").notifyClose();
  },
  handleOK : function(component, event, helper) {
    const evt = component.getEvent("confirmEvent");
    evt.fire();
    component.find("overlayLib").notifyClose();
  }
})

И еще понадобится Component Event

FlowButtonConfirmButtonBarConfirm.cmd

<aura:event type="COMPONENT" description="FlowButtonConfirmButtonBarConfirm">
</aura:event>

Когда код добавлен в вашу Org, можно использовать его в Flows.
Для использования компонента во Flow, нужно

  1. создать screen во flow
  2. Зайти на скрин
  3. Cлева в разделе “Screen Components” найти “FlowButton” и затянуть его себе на скрин.

В Flow это будет выглядеть следующим образом.

image

7 Likes

Привіт, дякую за код. Можна детальніше про RecordTabCloser?

І ще питання, в нас також є на проекті flow, але ми зтикнулися з багатьма проблемами, одна з яких не повна підтримка lightning framework, в мене була логіка, коли треба було редіректнутися на створений рекорд, вона не працювала, тому що, якщо flow визвати з кнопки на list view, то flow раниться в окремому вікні і тоді не повна підтримка lightning framework, але якщо закинути flow на page (створити в app builder) і створити tab до цієї сторінки, тоді flow виконується в контейнері lightning і весь функціонал працює.

Привет Богдан,
RecordTabCloser закину на днях, ну и опишу примерно, что к чему. Лады ?
Сложно сказать сразу, в чем проблема, но могу предположить, что если вы вызывали Flow с ListView (если честно не могу себе этого представить), то он просто не получал RecordId. А с PageLayout ему он доставался и ошибки не было.

Ні, я дебажив, рекорд айді є, сама логіка не працює, і шукав в інеті, найшов десь в документації, що flow, який раниться з action button, не всі ліби LT підтягує, і тоді певні компоненти не працюють. В моєму випадку не працювала навігація lightning:navigation, також навігація через e.force: $A.get(“e.force:navigateToSObject”) не працює. Короче фактично перекинутися із flow на створений рекорд не має змоги, якщо через action старутвали flow.

Вимушені були костилі робити через app builder page