Uncaught TypeError: Cannot read property 'displaytype' of undefined exception in Formula FIeld

  • 2
  • Problem
  • Updated 2 years ago
  • In Progress
When a formula field on Model A references a field on Model B, an exception "Uncaught TypeError: Cannot read property 'displaytype' of undefined" is encountered.

Notes
1) Model A is listed before Model B in the model page order
2) During evaluateFormulas, Model B is found, however when it calls 'getField' on Model B, fieldsMap is undefined

Steps to reproduce:
1) Create page using XML below
2) Preview page picking an account

Expected Behavior
Page renders successfully

Actual Behavior
Page does not render due to exception

Page XML
<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="true" showheader="true" tabtooverride="Account">   <models>
      <model id="Account" limit="1" query="true" createrowifnonefound="false" sobject="Account" adapter="" type="">
         <fields>
            <field id="Name"/>
            <field id="CreatedDate"/>
            <field id="FirstContactName" uionly="true" displaytype="FORMULA" readonly="true" returntype="TEXT" label="FirstContactName">
               <formula>{{$Model.Contact.data.0.Name}}</formula>
            </field>
         </fields>
         <conditions>
            <condition type="param" enclosevalueinquotes="true" operator="=" field="Id" value="id"/>
         </conditions>
         <actions/>
      </model>
      <model id="Contact" limit="" query="true" createrowifnonefound="false" adapter="" type="" doclone="" processonclient="true" sobject="Contact">
         <fields>
            <field id="Id"/>
            <field id="Name"/>
            <field id="AccountId"/>
            <field id="Account.Name"/>
         </fields>
         <conditions>
            <condition type="modelmerge" value="" field="AccountId" operator="=" model="Account" enclosevalueinquotes="true" mergefield="Id" novaluebehavior="noquery"/>
         </conditions>
         <actions/>
      </model>
   </models>
   <components>
      <pagetitle model="Account" uniqueid="sk-cNOcY-70">
         <maintitle>
            <template>{{Name}}</template>
         </maintitle>
         <subtitle>
            <template>{{Model.label}}</template>
         </subtitle>
         <actions>
            <action type="savecancel" window="self"/>
         </actions>
      </pagetitle>
      <basicfieldeditor showsavecancel="false" showheader="true" model="Account" mode="read" uniqueid="sk-cNOcY-71">
         <columns>
            <column width="50%">
               <sections>
                  <section title="Basics">
                     <fields>
                        <field id="Name"/>
                        <field id="FirstContactName" valuehalign="" type=""/>
                     </fields>
                  </section>
               </sections>
            </column>
            <column width="50%">
               <sections>
                  <section title="System Info">
                     <fields>
                        <field id="CreatedDate"/>
                     </fields>
                  </section>
               </sections>
            </column>
         </columns>
      </basicfieldeditor>
      <skootable showconditions="true" showsavecancel="true" showerrorsinline="true" searchmethod="server" searchbox="true" showexportbuttons="false" pagesize="10" createrecords="true" model="Contact" buttonposition="" mode="read" uniqueid="sk-cNaQf-118">
         <fields>
            <field id="Name"/>
         </fields>
         <rowactions>
            <action type="edit"/>
            <action type="delete"/>
         </rowactions>
         <massactions usefirstitemasdefault="true">
            <action type="massupdate"/>
            <action type="massdelete"/>
         </massactions>
         <views>
            <view type="standard"/>
         </views>
      </skootable>
   </components>
   <resources>
      <labels/>
      <css/>
      <javascript/>
   </resources>
   <styles>
      <styleitem type="background" bgtype="none"/>
   </styles>
</skuidpage>
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb

Posted 2 years ago

  • 2
Photo of Karen Waldschmitt

Karen Waldschmitt, Official Rep

  • 8,220 Points 5k badge 2x thumb
Barry~

We are still trying to figure out why you are getting the exception error but we've got a workaround for you that is actually probably more of a best practice way of doing things anyhow. We would recommend using a field editor on the contact model and a template field with a reference to account.name. Using templates is better because models load data THEN that data gets populated in the components. By using a template, the model data is loaded before Skuid starts trying to evaluate the merge syntax so there are no issues with dependency.

Here is the XML (your original page with slight modifications) that goes with the above recommendation. You will notice that the parent model is also above the child model, as it needs to be, in the composer. 
<skuidpage unsavedchangeswarning="yes" personalizationmode="server" showsidebar="true" showheader="true" tabtooverride="Account">
    <models>
        <model id="Contact" limit="" query="true" createrowifnonefound="false" adapter="salesforce" type="" doclone="" processonclient="true" sobject="Contact" service="salesforce">
            <fields>
                <field id="Id"/>
                <field id="Name"/>
                <field id="AccountId"/>
                <field id="Account.Name"/>
            </fields>
            <conditions>
                <condition type="modelmerge" value="" field="AccountId" operator="=" model="Account" enclosevalueinquotes="true" mergefield="Id" novaluebehavior="noquery"/>
            </conditions>
            <actions/>
        </model>
        <model id="Account" limit="1" query="true" createrowifnonefound="false" sobject="Account" adapter="salesforce" type="" service="salesforce">
            <fields>
                <field id="Name"/>
                <field id="CreatedDate"/>
                <field id="FirstContactName" uionly="true" displaytype="FORMULA" readonly="true" returntype="TEXT" label="FirstContactName">
                    <formula>{{$Model.Contact.data.0.Name}}</formula>
                </field>
            </fields>
            <conditions>
                <condition type="param" enclosevalueinquotes="true" operator="=" field="Id" value="id"/>
            </conditions>
            <actions/>
        </model>
    </models>
    <components>
        <pagetitle model="Account" uniqueid="sk-cNOcY-70">
            <maintitle>
                <template>{{Name}}</template>
            </maintitle>
            <subtitle>
                <template>{{Model.label}}</template>
            </subtitle>
            <actions>
                <action type="savecancel" window="self"/>
            </actions>
        </pagetitle>
        <basicfieldeditor showheader="true" showsavecancel="true" showerrorsinline="true" model="Contact" buttonposition="" uniqueid="sk-1kxwLK-154" mode="read">
            <columns>
                <column width="50%">
                    <sections>
                        <section title="Section A" collapsible="no">
                            <fields>
                                <field type="COMBO" valuehalign="" editmodebehavior="autopopup">
                                    <label>Account Name</label>
                                    <template>{{Account.Name}}</template>
                                </field>
                                <field id="Name" valuehalign="" type="">
                                    <label>First Contact</label>
                                </field>
                            </fields>
                        </section>
                    </sections>
                </column>
                <column width="50%">
                    <sections>
                        <section title="Section B">
                            <fields/>
                        </section>
                    </sections>
                </column>
            </columns>
        </basicfieldeditor>
        <skootable showconditions="true" showsavecancel="true" showerrorsinline="true" searchmethod="server" searchbox="true" showexportbuttons="false" pagesize="10" createrecords="true" model="Contact" buttonposition="" mode="read" uniqueid="sk-cNaQf-118">
            <fields>
                <field id="Name"/>
            </fields>
            <rowactions>
                <action type="edit"/>
                <action type="delete"/>
            </rowactions>
            <massactions usefirstitemasdefault="true">
                <action type="massupdate"/>
                <action type="massdelete"/>
            </massactions>
            <views>
                <view type="standard"/>
            </views>
        </skootable>
    </components>
    <resources>
        <labels/>
        <css/>
        <javascript/>
    </resources>
    <styles>
        <styleitem type="background" bgtype="none"/>
    </styles>
</skuidpage>

Hope this accomplishes what you were trying to do! 
Karen
(Edited)
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb
Hi Karen -

Thanks for looking in to this.  A few things:

1) Regarding figuring out the exception - I mentioned in my OP that fieldsMap is null and that is why the exception occurs.  Just want to confirm that you have reproduced this part and so when you say your still trying to figure out why the exception occurs, you mean that you're trying to figure out why fieldsMap is null - correct?

2) Regarding the template workaround, completely understand your reasoning and logic for the recommendation.  Unfortunately, templates don't provide the benefits that ui formula fields do - namely to be able to write code once and then re-use in other areas.  The sample repro that is in my OP is just to demonstrate the issue and doesn't really resemble what I'm doing in my real page.  I'm using a large chain of formulas to calculate different situations and the model order/formula eval issue is prohibiting that.  In my use case, I'm not even displaying the data that would be captured by the initial formula and hence the template doesn't achieve anything for me unfortunately.  Also, similar to Matt's issue (https://community.skuid.com/skuid/topics/formula-field-fails-when-referenced-model-has-no-data), I need to be able to use data.length, etc.

3) For those that do encounter this issue and where the template approach is appropriate for their use case, please note that the sample page you provided uses client side processing on Contact and server side processing on Account.  While completely valid, this is unlikely to be a standard way to approach model hydration and would return incorrect results if Page Caching was enabled.  Short story is some adjustments would need to be made depending on the specific use case.

Circling back to the core issue, the question really is why is fieldsMap null.  It's been a while since I've dug through the model initialization on initial page load but I think it goes through a model metadata, then the rows, then the next model, then the rows.  If I'm remembering correctly, this would likely explain why fieldsMap is null since Contact in my repro is Model #2 and it hasn't been fully initialized when Model #1 (Account) is initializing it's row which contains the field that points to Contact.  Again, I might not be remembering the code path correctly but this could be the reason.

Look forward to your thoughts and updates.  Thank you!
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Karen,

I'm in a similar same place as Barry. I need to use the formula field in rendering conditions. I was able to find a work-around for my specific use case, but a fix so pages don't break when we try to reference a model later in the model order would be ideal.