12

This is to me the most restricting drawback of Lightning compared to Visualforce. A way to dynamically bind/access properties like values of fields.

To make complex component structures fast I don't want to pass around queried SObjects. Instead I want to pass record Ids and field names. Lightning Data Service then fetches the record.

Saving this component:

<aura:component>
    <aura:attribute name="recordId" type="String" />
    <aura:attribute name="field" type="String" />
    <aura:attribute name="record" type="Object" access="private" />

    <force:recordData recordId="{!v.recordId}" targetFields="{!v.record}" layoutType="FULL" recordUpdated="{!c.init}" />

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

fails with:

Failed to save xyz.cmp: expecting a positive integer, found 'field' at column 10 of expression: v.record[field]: Source

I know that this currently is as designed and I'm not interested in "dirty" quickhacks. I want to know:

  • Is there any IdeaExchange I could vote for?
  • Is this on anyones roadmap?
  • What's the technical reason / design decision for not having this?
  • seems more like ideaexchange thing. – Pranay Jaiswal Nov 16 '17 at 20:07
  • 1
    I agree, this is painful. If you create an idea let us know :) – Fabien Taillon Nov 17 '17 at 9:38
  • @FabienTaillon I can't believe that there isn't one already... – Robert Sösemann Nov 17 '17 at 10:10
6

We understand that the ergonomics from a declarative point of view are great, but unfortunately there are big performance penalties and a bunch of quirks and functional issues supporting dynamic evaluation of expressions (ex. what would happen if you were to mutate the binding (bidirectional) in the children? - it will be very hard to mutate the object back given the dynamic expression).

Moreover, this approach will only solve very simple use cases, if you want to do any transformation or filtering, you will have to jump anyway to imperative code.

Here is a trivial workaround to achieve the same result:

({
  init: function (cmp) {
    var fields = Object.keys(cmp.get('v.record'));
    var filteredFields = fields.filter(function (f) { ... }) 
    cmp.set('v.filteredFields', filteredFields);
  }
})

Because of all of what I stated previously, I don't think this feature will be likely to be prioritized, at least not until we refactor the internals of how the expressions work.

  • Thanks for providing so much insight into the design decision and a great workaround as well. – Robert Sösemann Nov 19 '17 at 17:31
  • How would that work with force:inputField? – Robert Sösemann Nov 28 '17 at 11:21
  • 2
    Same thing. At the end of the day you just need to transform from an object to whatever array keys you need. In the case of force:fields: Object.values(contactObjectFromApex) If you for example in the future once we release lightning:inputFields components, you could transform to obtain the value and the type {value: "foo" type:"Percentage"}. You could do something like this: Object.keys(contactObj).map(function (key) { var valueObj = contactObj[key]; return { type : valueObj.type, value: valueObj.value } }); – Diego Dec 4 '17 at 4:32
  • Sorry for coming back again and again. But I just can get this done. Would you be so kind and provide component and ctrl code to make a component display a dynamic field value from a generic record queried by Data Service. I just can't make any sense out of your field filtering :-( – Robert Sösemann Dec 5 '17 at 10:55
  • 1
    Once I'm done with our release, I might have some time to help, but It would be great if you can provide me the foundation or a basic little example. – Diego Dec 6 '17 at 19:56
2

One can use the "getReference" function to programmatically create the dual binding between a record's field and its UI input. That way, as someone updates the inputs, the fields' values on the record are also automatically updated. Then one can validate and save as necessary later by inspecting the record(s) instead of potentially each UI input.

// Basic Usage Sample Code
var recordFieldReference = cmp.getReference('v.record.' + field.APIName);

inputComponent.set('v.value', recordFieldReference);

I haven't tested this with many records with many columns so how performant it may be is unknown but would like to find out.

See My Field Set Form Stack Overflow Comment For A More Detailed Example That Includes Dynamically Determining the UI Input Based On Type

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.