dynamically created model undefined

  • 1
  • Problem
  • Updated 3 years ago
  • Solved
I have the following custom field renderer:

'renderInitials': function (field, value) {		value = skuid.utils.decodeHTML(value);
var nurseModel = skuid.$M('Nurses');
if (!nurseModel) {
var runCreateNurseModel = skuid.snippet.getSnippet('createNurseModel');
nurseModel = runCreateNurseModel();
}
if (field.mode === 'edit'){
   var initials = [],
       currentRN = value,
       renderer = false,
       userId = skuid.utils.userInfo.userId;
   
   //get options for initials picklist    
   $.each(nurseModel.getRows(), function(i, row){
       initials.push({
           value: row.Initials__c,
           label: row.Initials__c
       });
       if (!currentRN && (row.Id == userId)) {currentRN = row.Initials__c}
   });
   
   //determine if we should set the default initials
   switch (field.id) {
       case 'RN_Initials_for_Test__c' :
           renderer = (field.model.getFieldValue(field.row, 'STD_Test_Method__c')) ? true : false;
           break;
       case 'RN_Initials_for_Results__c' :
           renderer = (field.model.getFieldValue(field.row, 'Results__c')) ? true : false;
           break;
       case 'RN_Initials_for_Reporting_to_Patient__c' :
           renderer = (field.model.getFieldValue(field.row, 'Results_Reported_to_Patient__c')) ? true : false;
           break;
       case 'RN_Initials_Reporting_to_Health_Dept__c' :
           renderer = (field.model.getFieldValue(field.row, 'Results_Reported_to_Health_Department__c')) ? true : false;
           break;
       case 'RN_Initials_for_Treatment__c' :
           renderer = (field.model.getFieldValue(field.row, 'STD_Treatment__c')) ? true : false;
           break;
   }
   
   //render picklist
   var customSelect = skuid.ui.renderers.PICKLIST.edit({
               entries : initials,
               required : false,
               defaultValue : (renderer) ? currentRN : ''
           }).change(function() {
               //  Update the row in the target object
               field.model.updateRow(field.row, field.id, $(this).val());
           });
   field.element.append(customSelect);
} else {
   skuid.ui.fieldRenderers.TEXT[field.mode](field,value);
}
}

If the 'Nurses' model doesn't exist, I'm running this createNurseModel snippet to create it:

'createNurseModel': function() {	
// Create dynamic model to capture nurse
nurseModel = new skuid.model.Model();
nurseModel.objectName = 'User';
nurseModel.id = 'Nurses';
nurseModel.fields = [
   { id: 'Id' },
   { id: 'Initials__c' }
];
nurseModel.orderByClause = 'Initials__c'
nurseModel.conditions = [
   { 
       type: 'fieldvalue', 
       field: 'UserRole.Name', 
       operator: 'contains', 
       value: 'RN',
       enclosevalueinquotes: true
   }
];
nurseModel.initialize();
$.when(nurseModel.load())
.then(function(){
return nurseModel;
});
}

However, I'm getting the error that nurseModel is undefined when the field renderer tries to call getRows() on it in the $.each() in bold.

Is there something I'm missing here? Do I have to somehow get the field renderer snippet to wait until the createNurseModel snippet actually returns a model? And if so, how can I do that? Can I somehow return both a jQuery deferred promise and a model in the return statement after I create the model?
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb

Posted 3 years ago

  • 1
Photo of Ben Hubbard

Ben Hubbard, Employee

  • 12,490 Points 10k badge 2x thumb
Your createNurseModel function doesn't actually return anything so nurseModel will be undefined.  You could have the createNurseModel function return a promise instead.

nurseModel.initialize();

var myDeferred = new $.Deferred();

$.when(nurseModel.load()).then(function(){
	myDeferred.resolve(nurseModel);
});

return myDeferred.promise();

Then you would wait for your deferred to resolve in your custom renderer before rendering.
Photo of Matt Sones

Matt Sones, Champion

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

I'm lost. What does
return nurseModel; 
do, if it's not returning the model?


Should I use 
$.when(nurseModel.initialize().load())
.then(function(){
return nurseModel;
});
instead of
nurseModel.initialize();
$.when(nurseModel.load())
.then(function(){
return nurseModel;
});
???


Previously, I was returning a myDeferred.resolve() on $.when.done (but without nurseModel as an argument), and then trying to use skuid.$M() to get e reference to the model I just created. But it wasn't working for me. skuid.$M() kept returning undefined.
Photo of Ben Hubbard

Ben Hubbard, Employee

  • 12,490 Points 10k badge 2x thumb
Your return statement in the code above is the return value of the nested anonymous function, not the return value of the createNurseModel function.

You can learn more about the jQuery then() function here.

I think the reason skuid.$M() was not working is that you never registered your model.

try changing nurseModel.initialize() to nurseModel.initialize().register()
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Ah, thanks for the explanation!

So, if I use
var myDeferred = new $.Deferred();

$.when(nurseModel.initialize().register().load()).then(function(){
	myDeferred.resolve(nurseModel);
});

return myDeferred.promise();
should createNurseModel() return the model along with the promise? Will the following lines in my field renderer code work?
var runCreateNurseModel = skuid.snippet.getSnippet('createNurseModel');
nurseModel = runCreateNurseModel();
Or should I still use skuid.$M() to get the model?

I've tried to read through the jQuery deferred documentation, but my brain is struggling...
Photo of Ben Hubbard

Ben Hubbard, Employee

  • 12,490 Points 10k badge 2x thumb
I would do something like this...


var nurseModel = skuid.$M('Nurses');

var myActualRendering = function() {
	// Put all of your custom rendering code in here
	// This will only run when nurseModel is ready
};

if (!nurseModel) {
	var runCreateNurseModel = skuid.snippet.getSnippet('createNurseModel');
	var myAwesomePromise = runCreateNurseModel();

	$.when(myAwesomePromise).then(function(resolvedModel){
		// Either should work
		nurseModel = resolvedModel;
		// nurseModel = skuid.$M('Nurses');

		// Do your rendering work here
		myActualRendering();

	});

} else {
	// Do your rendering work here
	myActualRendering();	
}
Photo of Matt Sones

Matt Sones, Champion

  • 31,478 Points 20k badge 2x thumb
Slick. That make sense!

Thanks for your help, Ben!