8

Lightning Data Service is great. Multiple components are magically linked to database records. When records change in the db component show that change.

Imagine this to work without saving change to the database. Imagine a Lightning page with multiple components that edit a set of records. A user changes a record field in component B and the change is shown instantely in component B. No DML involved. Or think of editable database table displaying Totals rows or columns. This must be doable without any database back and forth.

My idea was that I just need to build something as the Data Service that works instantely. Components pass it an recordId and get a reference of that record. If the components then display or edit the record directly (by-reference and not by-value) all other components having the same reference should be "notified" of changes.

But...it doesn't work. Calculated fields don't see the changes :-(


This sequence diagram tries to explain the code listed below.

enter image description here

editGrid.cmp

<aura:component controller="EditableGridCtrl">
    <aura:attribute name="data" type="Grid" />
    <aura:attribute name="recordsById" type="Map" />

    <aura:handler name="init" value="{!this}" action="{!c.init}" />
    <aura:handler name="requestRecord" event="c:strike_evt" action="{!c.passRecord}" />

    <c:strike_dataGrid data="{!v.data}" />
</aura:component>

editGridController.js

init: function(cmp, evt, helper) {
    var records = helper.queryFromApex(cmp);
    cmp.set("v.recordsById", records);
    cmp.set("v.data", helper.toStrikeFormat(records));
},

passRecord: function(cmp, evt, helper) {
    var source = evt.getSource();
    var recordId = helper.getRecordId(evt);
    var record = helper.getRecord(recordId);
    source.setRecord(record);
}

Strike Data Json (10 columns, 100 rows)

{   
    "columns":[
        { "label":"Price", "dataType":"COMPONENT", "name":"price" },
        { "label":"Cost", "dataType":"COMPONENT", "name":"cost" },
        ...
        { "label":"Margin", "dataType":"COMPONENT", "name":"margin" }
    ],
    "rows":[
        {
            "price":{
                "type":"c:inputCell",
                "attributes":{ "recordId":"00690000002BoMV", "field":"Price" }
            },
            "cost":{
                "type":"c:inputCell",
                "attributes":{ "recordId":"00690000002BoMV", "field":"Cost" }
            },
            "margin":{ "type":"c:marginCell",
                "attributes":{ "recordId":"00690000002BoMV" }
            }
        },
        ...
    ]

inputCell.cmp

<aura:component implements="force:hasRecordId">
    <aura:attribute name="field" type="String" />
    <aura:attribute name="record" type="Map" />

    <aura:register name="requestRecord" event="c:strike_evt" />
    <aura:handler name="init" value="{!this}" action="{!c.requestRecord}" />

    <aura:method name="setRecord" action="{!c.setRecord}">
        <aura:attribute name="record" type="Map" />
    </aura:method>

    <lightning:input value="{!v.value}" />
</aura:component>

inputCellController.js

init: function(cmp, evt, helper) {
    cmp.getEvent("requestRecord")
        .setParams({ data: cmp.get("v.recordId") })
        .fire();
},

setRecord: function(cmp, evt, helper) {
    var params = event.getParam("arguments");
    cmp.set("v.record", params.record);
}

marginCell.cmp

<aura:component implements="force:hasRecordId">
    <aura:attribute name="record" type="Map" />
    <aura:attribute name="margin" type="Decimal" />

    <aura:register name="requestRecord" event="c:strike_evt" />
    <aura:handler name="init" value="{!this}" action="{!c.requestRecord}" />
    <aura:handler name="change" value="{!record}" action="{!c.updateMargin}" />

    <aura:method name="setRecord" action="{!c.setRecord}">
        <aura:attribute name="record" type="Map" />
    </aura:method>

    <ui:outputNumber value="{!v.margin}" ... />
</aura:component>

marginCellController.js

requestRecord: function(cmp, evt, helper) {
    // same as in inputCellController.js 
},

setRecord: function(cmp, evt, helper) {
    var params = event.getParam("arguments");
    cmp.set("v.record", params.record);
},

updateMargin: function(cmp, evt, helper) {
    var record = cmp.get("v.record");
    cmp.set("v.margin", record.Price__c - record.Cost__c);
}
  • 1
    Is the binding triggering when you set v.margin manually to a hardcoded value rather an inline calculation using fields of your data structure (I guess the code of updateMargin is triggering anyway)? Shooting in the blind: try to set v.margin to a null value right before setting it to the real new value. Sidenote: type="Grid" in the editGrid is not a valid type – Christian Menzinger Dec 7 '17 at 13:03

Your Answer

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

Browse other questions tagged or ask your own question.