2

I've built nested lightning components available for a contact page. There are three components: the Pane which sits on the record home page this has three tabs one tab is a text field, the other two tabs are used to display different nested components. One of these components is a list of tasks. Clicking on the subject of a task in the list fires an force:editRecord event. This successfully brings up the window and any changes are saved. However it does not refresh the view. I've tried accomplishing this in a couple ways.

I tried implementing the method suggested here, which handles a force:refreshView event and uses aura:dependency.

I also tried handling a force:saveRecordSuccess however the associated controller code was not being accessed as evidenced by no console logs.

I've attempted putting the handlers in both the child component and the parent Pane component with no difference in behavior.

Lastly I tried window.location.reload(); after firing the editRecord event but it reloads the page before bringing the edit page up.

List component markup

<aura:component controller="AccountDevelopmentTaskController" access="global" implements="force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId">
<aura:attribute name="challenges" type="Task[]" access="GLOBAL"/>
<aura:attribute name="id" type="String" access="GLOBAL"/>
<aura:handler name="init" value="{!this}" action="{!c.start}"/>
<aura:dependency resource="markup://force:editRecord" type="EVENT"/>
<aura:handler event="force:refreshView" action="{!c.start}"/>

<div class="slds-container--fluid">
    <table class="slds-table slds-table_bordered slds-table_cell-buffer">
        <thead>
         ...
        </thead>
        <tbody>
            <aura:iteration var="chlng" items="{!v.challenges}">
                <tr>
                    <th scope="row" data-label="Challenge">
                        <div class="slds-truncate slds-text-link" title="">
                            <div data-record="{!chlng.Id}" onclick="{!c.showEditPanel}">
                                <ui:outputText value="{!chlng.Subject}" class="slds-text-link_reset" />
                            </div>
                        </div>
                    </th>
                    ...
                </tr>
            </aura:iteration>

List component controller

 start : function(component,event,helper) {
    var id = component.get("v.id");
    var action = component.get("c.loadChallenges");
    action.setParams({"tId":id});
    action.setCallback(this,function(response){
        var tasks = response.getReturnValue();
        component.set("v.challenges",tasks);
    });
    $A.enqueueAction(action);
},

showEditPanel : function(component,event,helper){
    var editRecordEvent = $A.get("e.force:editRecord");
    var selectedItem = event.currentTarget;
    var recId = selectedItem.dataset.record;
    component.set("v.currParamId",recId);
    editRecordEvent.setParams({
        "recordId" : recId
    });
    editRecordEvent.fire();

}

Here is the Pane component compacted to the relevant bits:

<aura:component controller="AccountDevelopmentTaskController" access="global" implements="force:appHostable,flexipage:availableForRecordHome,force:hasRecordId">
  <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
  <aura:attribute name="msg" type="String" access="GLOBAL"/>
  <lightning:tabset class="slds-box" >
    ...
     <lightning:tab label="Challenge">
        <c:ADChallengeList id="{!v.recordId}" /> ...
  • did you try introducing a timeout before the refresh? if you do make sure to use $A.getCallback(function() : developer.salesforce.com/docs/atlas.en-us.lightning.meta/… – Rao Sep 29 '17 at 16:30
  • @Rao no there are no timeouts in my code, are you saying I should or to watch out for this if I do? – Josh D Sep 29 '17 at 16:54
  • nope, you said the window.refresh fires before the force:editrecord. I am suggestion you to introduce a time out before you fire the reload – Rao Sep 29 '17 at 16:58
  • I gave it a shot. It supersedes the edit page. What I mean is it reloads whether or not you have clicked the save button. And the handlers for recordSaveSuccess don't seem to be tripping. I suppose I could set 30 seconds for a timeout to give time to save the record before the reload. But it's not ideal – Josh D Sep 29 '17 at 17:07
  • 1
    So reading around looks like force:recordsavesuccess works wth force:recordedit component not an event. We may have to get creative and find other solutions salesforce.stackexchange.com/questions/157329/… – Rao Sep 29 '17 at 18:17
2

Update: I did not factor in the part that you are clicking on a specific record and geetting the record Id. updated the code to take in the selected record Id and pass it to the force:recordEdit component.

Note to others: The OP reported that this implementation was browser dependent, he was having issues on chrome v.61 /32 bit version, and had no issues on 64 bit version/IE

Here we go,, this is the craziest thing I have done in a long time. I recreated the whole $A.get("e.force:editRecord") event to gain control of the save button.

First the Output:

enter image description here

This code involves

1) Winter 18 developer edition.

2) Dynamically creating the force:recordedit component and save button and wiring the save button to call the recordsave (event). Because I used force:recordedit component I now get to use recordsavesuccess.

<aura:handler name="onSaveSuccess" event="force:recordSaveSuccess" action="{!c.start}"/>

3) An event that can self handle itself : I created the custom event just to call the handleedit function by passing the selected record ID from the list of challenge records in my component. From here we can start creating the dynamic components as required.

Ref: https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/events_component_fire.htm

4)Idea taken from this post (Aura Id of dynamic component is coming back as undefined) Aura:Id of dynamically created compontns cannot be accessed

5) A modal concept to mimic force:recordedit event (note I have created force:recordedit component and mimicked it to look like $A.get("e.force:editRecord") event)

http://www.sfdcmonkey.com/2017/04/15/modal-box-lightning-component-salesforce/

Now to the code

App:

<aura:application extends="force:slds">
    <c:forceeditsavesuccesscomp></c:forceeditsavesuccesscomp>
</aura:application>

Component: I have defaulted the task Id, you can use {!v.recordId} or however you want to populate the Id of the record. Used some SLDS html to mimic the modal like feeling.

<aura:component controller="AccountDevelopmentTaskController" access="global" implements="force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId">
    <aura:registerEvent name="handleedit" type="c:handleeditevent"/>

    <aura:attribute name="challenges" type="Task[]" access="GLOBAL"/>
    <aura:attribute name="id" type="String" access="GLOBAL" default="00TB0000005p4cVMAQ"/>
    <aura:handler name="init" value="{!this}" action="{!c.start}"/>
    <aura:handler name="handleedit" event="c:handleeditevent" action="{!c.handleedit}" />
    <aura:handler name="onSaveSuccess" event="force:recordSaveSuccess" action="{!c.start}"/>

    <aura:attribute name="isOpen" type="boolean" default="false"/>

    <div class="slds-container--fluid">
        <table class="slds-table slds-table_bordered slds-table_cell-buffer">
            <thead>
                Subject
            </thead>
            <tbody>
                <aura:iteration var="chlng" items="{!v.challenges}">
                    <tr>
                        <th scope="row" data-label="Challenge">
                            <div class="slds-truncate slds-text-link" title="">
                                <div data-record="{!chlng.Id}" onclick="{!c.showEditPanel}">
                                    <ui:outputText value="{!chlng.Subject}" class="slds-text-link_reset" />
                                </div>
                            </div>
                        </th>
                        ...
                    </tr>
                </aura:iteration>
            </tbody>
        </table>
    </div>
    <aura:if isTrue="{!v.isOpen}">
    <div class="demo-only" style="height: 640px;">
        <section role="dialog" tabindex="-1" aria-labelledby="modal-heading-01" aria-modal="true" aria-describedby="modal-content-id-1" class="slds-modal slds-fade-in-open">
            <div class="slds-modal__container">
                <header class="slds-modal__header">
                    <button class="slds-button slds-button_icon slds-modal__close slds-button_icon-inverse" title="Close">
                        <span class="slds-assistive-text">Close</span>
                    </button>
                    <h2 id="modal-heading-01" class="slds-text-heading_medium slds-hyphenate">Modal Header</h2>
                </header>
                <div class="slds-modal__content slds-p-around_medium" id="modal-content-id-1">
                    {!v.body}
                </div>
            </div>
        </section>
        <div class="slds-backdrop slds-backdrop_open"></div>
    </div>
    </aura:if>
</aura:component>

Controller:

    ({
    start : function(component,event,helper) {
        var id = component.get("v.id");
        var action = component.get("c.loadChallenges");
        action.setParams({"tId":id});
        action.setCallback(this,function(response){
            var tasks = response.getReturnValue();
            component.set("v.challenges",tasks);
        });
        $A.enqueueAction(action);
    },

    showEditPanel : function(component,event,helper){
        var selectedItem = event.currentTarget;
        var recId = selectedItem.dataset.record;
        component.set("v.isOpen", true);        
        var compEvent = component.getEvent("handleedit");
        compEvent.setParams({
            "selectedId": recId
        }).fire();
    },
    handleedit: function(component,event,helper){
        /*createComponentController.js*/

        $A.createComponents([
            ["force:recordEdit",
             {
                 "aura:id": 'editrecord',
                 "recordId": event.getParam("selectedId")
             }],
            ["lightning:button",
             {
                 "aura:id" : 'savebutton',
                 "label": "Save record", 
                 "onclick": component.getReference("c.handlePress")
             }]
        ],
                            function(editcomp, status, errorMessage){
                                //Add the new button to the body array
                                if (status === "SUCCESS") {
                                    var editval = editcomp[0];
                                    var button = editcomp[1];
                                    var body = component.get("v.body");
                                    body.push(editval);
                                    body.push(button);
                                    component.set("v.body", body);
                                }
                                else if (status === "INCOMPLETE") {
                                }
                                    else if (status === "ERROR") {

                                    }
                            }
                           );
    },
    handlePress : function(component) {
        //component.find always comes back as undefined. Look at point 4.
        console.log('#######'+ component.find("editrecord"));
        component.find({ instancesOf : "force:recordEdit" })[0].get("e.recordSave").fire();
        component.set("v.isOpen", false);
        // the body was rendering differently on second click after saving the modal ( assuming this could be due the way the component's init is being handled by calling the start method, but as a dirty fix I used location.reload() to get back to original state)
        window.location.reload();

    }

})

Event:

<aura:event type="COMPONENT" description="Event template" >
    <aura:attribute Name="selectedId" type="String" access="global"/>
</aura:event>

controller:

//I am returning a bunch of tasks here, I am assuming you are passing a contact/account Id and gathering the tasks related to the selected record.Rewire this controller as required.

public class AccountDevelopmentTaskController {

    @AuraEnabled
    public static Task loadChallenges(id tId){
        return [select id,Subject from task where Id=:tId];
    }
}
  • wow! Thanks a lot! Give me a chance to scratch my head and implement this and I'll give you the accepted answer as soon as I'm done! – Josh D Sep 29 '17 at 20:19
  • most welcome, I had great fun learning so many thing trying this POC :). Let me know how it goes for you – Rao Sep 29 '17 at 20:20
  • one thing I did not do was create a cancel / close button , look around you will easily find resources to create a close button dynamically and push it into this example. – Rao Sep 29 '17 at 20:24
  • @JoshD Look at the update I posted. – Rao Sep 29 '17 at 20:45
  • I noticed that issue just about the time you posted the update :) Everything seems to be working up until I click the 'Save record' button. I get this component error: Uncaught Action failed: c:ADChallengeList$controller$handlePress [Cannot read property 'fire' of null] for some reason it's not finding the dynamically created component I guess? – Josh D Sep 29 '17 at 21:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.