Dynamic model createRowIfNoneFound prevents .load()

  • 1
  • Problem
  • Updated 2 years ago
I have a custom component which is creating a dynamic model. I need the model to have the createRowIfNoneFound porperty = true.

Problem is that when it comes time for model.initialize().register().load(), the code breaks on .load() because there are 'changes' in the model. However, here is what the model changes object looks like in the console:



There's nothing to see.

What's up with that?

I'd prefer to not have to manually recreate the 'createRowIfNoneFound' behavior.
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb

Posted 2 years ago

  • 1
Photo of Matt Sones

Matt Sones, Champion

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

I've confirmed that the .createRowIfNoneFound is the problem.

When I remove that property from the model, and then after load call the following, I get the expected result.
//Replacement for .createRowIfNoneFound
if (!brochureModel.getRows().length) brochureModel.createRow();
Definitely a hacky work-around. Skuid should be able to load dynamically created models with createRowIfNoneFound = true.
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb
Hey Matt -


Can you be more specific when you say "...the code breaks..."? Is there an exception thrown? Some type of error message?


I know that Skuid contains code that will not allow a model to load when there are changes in the model (that line of code inside the runtime has bitten me in the past). I'm guessing you are probably encountering an unhandled exception on that line of code but just want to confirm.


In your screen shot, there are changes. It's that Row Id '1' was created - it's just no field values are set yet which is why you might be thinking there are no changes.


Before determining if there is something in your code that might be wrong or if this potential bug, if you could let me know what you mean by "breaks" and also if you could put together just a simple sample that would be helpful. The fact that it's inside of a custom component shouldn't matter so isolating this down to a blank page with a simple dynamic model creation should narrow down surface area.
(Edited)
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Hey Barry. Thanks for pursuing the details... sorry for the vagueness.

Yes, an exception is thrown at .load() indicating that the model can't be updated/queried because there are changes.

Here's the code for my component... it's just a field editor with a reference field and a checkbox that creates its own dynamic model with conditions based on its properties.

// Brochure Component     skuid.componentType.register('ccoptimize__brochure',function (element,xmlDef,component){
        // Get properties and model
        var brochureCode = xmlDef.attr('code'),
            brochureLabel = 'Literature__' + xmlDef.attr('brochure'),
            caseModelId = xmlDef.attr('casemodel'),
            caseFieldId = xmlDef.attr('casefield');
        // Set variables
        var brochureModelId = (brochureLabel) ? brochureLabel.replace(/[^A-Z0-9\_]+/ig, "") : 'Literature__' + randomString(4),
            caseModel = skuid.$M(caseModelId),
            caseValue = caseModel.getFieldValue(caseModel.getFirstRow(),caseFieldId);
        // Generate Brochure Model
        var brochureModel = new skuid.model.Model();
        brochureModel.objectName = 'Literature__c';
        brochureModel.id = brochureModelId;
        brochureModel.recordsLimit = 1;
        // brochureModel.createRowIfNoneFound = true;
        brochureModel.fields = [
            { id: 'Brochure_Name__c'},
            { id: 'Brochure_Name__r.Name'},
            { id: 'Brochure_Given__c'}
        ];
        brochureModel.conditions = [
            {
                type: 'fieldvalue',
                field: 'Brochure_Name__r.Brochure_Code__c',
                operator: '=',
                value: brochureCode,
                encloseValueInQuotes: true
            },
            {
                type: 'fieldvalue',
                field: 'Patient_Case__c',
                operator: '=',
                value: caseValue,
                encloseValueInQuotes: true
            }
        ];
        // Define XML for our child components
        var xmlFieldEditor = $xml('<basicfieldeditor showheader="true" showsavecancel="false" showerrorsinline="true" model="'+brochureModelId+'" mode="edit"/>').append(
            $xml('<columns/>').append(
                $xml('<column width="100%" />').append(
                    $xml('<sections/>').append(
                        $xml('<section title="Brochure" collapsible="no" showheader="true"/>').append(
                            $xml('<fields/>').append(
                                $xml('<field id="Brochure_Name__c" valuehalign="" type="REFPICK" optionsource="" required="true"/>').append(
                                    $xml('<filters><filter type="fieldvalue" operator="=" enclosevalueinquotes="true" field="Brochure_Code__c" value="'+brochureCode+'"/></filters>'),
                                    $xml('<searchfields/>')
                                    ),
                                $xml('<field id="Brochure_Given__c" valuehalign="" type=""/>')
                                )
                            )
                        )
                    )
                )
            );
        // Make containers for our components
        var brochureContainer = $('<div id='+brochureModelId+'>');
        // Load brochure model
        $.when(brochureModel.initialize().register().load()).then(function(){
            skuid.component.factory({
                xmlDefinition: xmlFieldEditor,
                element: brochureContainer
            });
            // Add components to the DOM element
            element.append(brochureContainer);
            //Replacement for .createRowIfNoneFound
            if (!brochureModel.getRows().length) brochureModel.createRow();
        });
    });
Photo of Tanzir Riad

Tanzir Riad

  • 414 Points 250 badge 2x thumb
Hello Barry,
I am working on creating dynamic model for one of my project and took your code sample as a start. the problem I am facing is getting the error "Cannot read property 'getAdapter' of undefined"
when it hit this line:
  accountModel.initialize().register();

Do you have any idea what I am missing?

Thanks,
Tanzir
(Edited)
Photo of Matt Sones

Matt Sones, Champion

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

Try adding
accountModel.adapterName = "salesforce";
into your model definition.
(Edited)
Photo of Tanzir Riad

Tanzir Riad

  • 414 Points 250 badge 2x thumb
Thanks Matt,
But I am still getting this error. I am attaching the code. if you can tell what I am missing that will be a great help:

var element = arguments[0], $ = skuid.$;

alert('starting work');
     var accountModel = new skuid.model.Model();
     accountModel.objectName = 'Account';
     accountModel.adapterName = "Salesforce";
     accountModel.id = 'Account';
     accountModel.recordsLimit = 1;
     accountModel.createRowIfNoneFound = true;
     accountModel.fields = [
         { id: 'Id' }
         , { id: 'Name' }
        ];
        accountModel.conditions = [
            {
                type: 'fieldvalue'
                , field: 'Name'
                , operator: '='
                , value: 'FiddlyFooBar'
                , encloseValueInQuotes: true
            }
        ];
        accountModel.initialize().register();
        alert('registered model');

        // register creates a row since createRowIfFound is marked to true
        // so we must cancel the changes in order for load to complete successfully
        accountModel.cancel();
        
        $.when(accountModel.load())
            .done(function() {
                console.log(accountModel);
            })
            .fail(function() {
               console.log('failed to load!!') ;
            });
Photo of Tanzir Riad

Tanzir Riad

  • 414 Points 250 badge 2x thumb
I made it working. I had add an empty model in skuid. It seems little confusing on why I have to have an empty model
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb
Hello Tanzir -

You have encountered a Skuid bug.  I just created another post to track the issue - see https://community.skuid.com/skuid/topics/js-exception-encountered-on-dynamic-model-initialize-when-n... for details.

The workaround, as you found, is to create a declarative model on the page making sure to have load data and create row if none both set to False (not checked) to avoid any unnecessary additional performance impact.  The model will result service adapter getting registered which is what you need to make your dynamic model work properly.

Matt - In this case, the adapterName shouldn't be needed as Skuid will default "saleforce" to the adapter name if the property is empty.  Just FYI.
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb
Skuid Team -

In the comments above, I had asked some questions to help better shape Matt's issue but there hasn't been a response to them.

Can someone please provide some insight to the questions at https://community.skuid.com/skuid/topics/dynamic-model-createrowifnonefound-prevents-load?topic-repl...?

Thanks!
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb
Skuid Team - Any insight on this?
Photo of Barry Schnell

Barry Schnell, Champion

  • 18,076 Points 10k badge 2x thumb
Skuid Team -

Can someone please provide some insight to the questions at https://community.skuid.com/skuid/topics/dynamic-model-createrowifnonefound-prevents-load?topic-repl...?

Thank you!