apex-enterprise-patterns/force-di

Add data type conversion support in injectorFlowProxyController.js

Closed this issue · 5 comments

Currently, the code maps the injector attributes to flow input variables and sets the data type as String but the code needs to be doing better inference on the injector attribute data type to identify boolean, number, date, etc.

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

image

@afawcett @ImJohnMDaniel I believe we are at an architectural decision making point before moving forward on this issue.

To map the injector attribute values to flow input variables, then we need to know the intended data type the injector attributes represent in the flow.

Relying on javascript's typeof or instanceof keywords is not sufficient because, for example, Date and DateTime values returned from apex methods and stored in <aura:attribute type="Date"> and <aura:attribute type="DateTime"> tags are still passed around among the components as JSON, which is just text.

What I'm seeing is that regardless what type I specify for <aura:attribute type="Date"> or <aura:attribute type="DateTime">, the data type of those attributes are passed to <c:injectorAttribute> and obtained by the injector's js controller as JSON. So when I do typeof injectAttr.get('v.value') then I'm getting string. So it is very ambiguous whether the developer wanted to pass a literal text value as "2018-07-28" or the date value.

Options

Option 1

My preferred approach would be that we leverage the Flow's metadata and infer the data type based on matching injector attribute names to flow input variable names.

However, to complicate things, since we're in Lightning, I can't easily retrieve the expected Flow input variables from either the REST API (only works if it's autolaunched/headless by the way) or the Metadata API (for any flow type) without using a Named Credential. This limitation Andy and I have discussed at length on other projects.

Option 2

Since option 1 requires undue burden of Named Credential, I believe we need the <c:injectorAttribute> tags to include a third property to indicate their intended data type.

<aura:component>
    <aura:attribute name="name" type="String"/>
    <aura:attribute name="value" type="Object"/>
    <aura:attribute name="type" type="String"/>
</aura:component>
<c:injector bindingName="flow_AccountRecord">
    <c:injectorAttribute name="recordId" value="{!v.recordId}" type="String"/>
    <c:injectorAttribute name="myDate" value="{!v.myDate}" type="Date"/>
    <c:injectorAttribute name="myDateTime" value="{!v.myDateTime}" type="DateTime"/>
</c:injector>

For reference, here is example code using MetadataService.cls to retrieve Flow input variable information.

This does fail when called from Apex class in Lightning component context due to invalid session id, as expected. Hence a need for Named Credential, so I'm leaning towards implementing this with adding dataType property to <c:injectorAttribute> component until/if such a time where Named Credentials aren't necessary to make API callouts from Apex in Lightning.

However, even though going through Metadata API route means we can infer the data types, the Metadata API requires the flow version as part of the API name when retrieving the information. This would mean that in the CMDT, the developer would need to somehow indicate the flow version. We wouldn't want it to be part of the flow name itself, I don't think, because in visualforce and apex contexts we can invoke a flow without specifying the version.

    private static void testGetFlowMetadata() {
        
        MetadataService.MetadataPort service = new MetadataService.MetadataPort();
        service.SessionHeader = new MetadataService.SessionHeader_element();
        service.SessionHeader.sessionId = UserInfo.getSessionId();
        
        MetadataService.ReadFlowResult result = (MetadataService.ReadFlowResult) service.readMetadata('Flow', new String[] { 'AccountRecordFlowVF-4' });
        for ( MetadataService.Flow f : result.records ) {
            System.debug(f);
            for ( MetadataService.FlowVariable var : f.variables ) {
                System.debug('\t' + 'name=' + var.name + ', dataType=' + var.dataType + ', isInput=' + var.isInput + ', isOutput=' + var.isOutput + ', isCollection=' + var.isCollection + ', objectType=' + var.objectType);
            }
            System.debug('---');
        }
        
    }

Just to bring this thread up to speed. @douglascayers, based on side discussions, it appears that better option is option 2 -- "<c:injectorAttribute> tags to include a third property to indicate their intended data type". Is that accurate?