Inputs not attached to Object Models?

Charlie JonasCharlie Jonas Member
edited March 2017 in Questions
I'm working on an API integration with a system where we want to send orders from within my clients ORG. There are a number of variable configuration pieces that I retrieve directly from a webservice. These configurations are not stored in SF, thus I'm finding it awkward to use skuid to display & select these. For example, after getting the shipping address for the order, I make a callout to get available shipping methods. These are then displayed to the user for selection. Currently, I'm doing this either by injecting the inputs with javascript (using a component). Functionally this works fine, but the injected components obviously are not styled with the rest of the page. I was just wondering if there are any best practices for doing this type of thing, or if I will just have to use CSS to make everything fit. (this is my last question today, I promise ;)

Comments

  • Zach McElrathZach McElrath Skuad
    edited March 2017
    (By the way, I'm not an automated documentation-writing troll, despite popular clamor and evidence to the contrary.) Okay, this is also a good question, and while the solutions are not "ideal", we use them both often and have no qualms about recommending them. SOLUTION 1: Define your inputs as real fields in Salesforce. This one's obvious, but I'm putting it here just for posterity and to reassure people that you don't have to do Solution 2 to make this work. SOLUTION 2: Use a Custom Field Renderer. These things are magical, and for JavaScript junkies, they take Skuid to a whole different level. Basically, drag in an old actual field, e.g. the Id field, on your regular Model, into your Field Editor or Table, and then change its Label to your desired label, and set Field Renderer to "Custom (Run Snippet)", and then enter "FakeInput" as the Snippet name: Then add the following JavaScript Resource of type "Inline (Snippet)":
          var field = arguments[0],      value = '', // We could set a default value here, if we want      $ = skuid.$;    var fieldId = 'MyFakeField__c';    // Define custom metadata for our fake field,  // so that Skuid knows how to run it.  var metadata = {       id: fieldId,     displaytype: 'PICKLIST',     accessible: true,     createable: true,     editable: true,      // If set to true,       // then the default option should be chosen     required: false,      picklistEntries: [        { value: 'Option1', label: 'Option 1', active: true, defaultValue: true },        { value: 'Option2', label: 'Option 2', active: true, defaultValue: false },        { value: 'Option3', label: 'Option 3', active: true, defaultValue: false }     ]  };    // Add our fake metadata to our fields map  if (!field.model.fieldsMap[fieldId]) {     field.model.fields.push(metadata);     field.model.fieldsMap[fieldId] = metadata;  }    field.metadata = metadata;  field.mode = 'edit';    // Run the standard renderer  skuid.ui.fieldRenderers[metadata.displaytype][field.mode](field,value);    
    Let me explain what's going on here. Custom Field renderers get handed a skuid.ui.Field object representing the Input Field on the page. skuid.ui.fieldRenderers is documented in the skuid.ui object docs and allows you to run a Skuid Ui Renderer for any DisplayType, e.g. PICKLIST, CURRENCY, REFERENCE, TEXTAREA, etc., for a particular Mode, e.g. read, readonly, edit, on a particular skuid.ui.Field object, with a given starting value. So all we're doing here that's "weird" is that we're defining the Field's Metadata here in JavaScript rather than retrieving it from Salesforce. So here we're doing a Picklist Field, adding 3 Options to it, making it not-required, etc. So here's what it looks like:
  • Charlie JonasCharlie Jonas Member
    edited January 2014
    Once again, great answer! Solution 2 is exactly what I'm looking for; Adding the fields is not an option as we are working with the Task object (limited to 100 custom fields, i think). While it does seem like a little bit of a hack its definitely a better solution than what I'm currently doing. 3 for 3 on resolving all of my projects blocking issues; someone buy this man a beer.
  • Charlie JonasCharlie Jonas Member
    edited January 2014
    Actually I do have one more tinsy question... What is the best way to retrieve the value of this field? I added a change handler to the editor: field.editor.handleChange = function(e) { e.changes['OBJECTID'].OrigionalField__c } but referencing the field value is not quite as clean as I had hoped... I can do this to allow it to be more agnostic to the dummy object I'm using: e.changes[Object.keys(e.changes)[0]].OrigionalField__c; Also seems strange that even though I change id in the metadata, the change event still references the original field? Wondering if it is also changing the underlying model as well. If I actually update field.id it resolves this. I can definitely get by like this but I just wanted to make sure there isn't a better way I should be doing this.
  • Zach McElrathZach McElrath Skuad
    edited March 2017
    Assuming that we've added the Field to the Model's Metadata, which we did in the example above by modifying field.model.fields and field.model.fieldsMap, we should be able to retrieve the value of the Field using the standard model.getFieldValue(row,field,[noEscape]) syntax, e.g. var model = field.model, row = field.row; var fakeFieldValue = model.getFieldValue(row,'FakeField__c');
  • Charlie JonasCharlie Jonas Member
    edited January 2014
    Zach, I've run into a bit of a block. I need to programmatically set these fields. The following code works fine for "real" fields, but it doesn't have any affect on the ones I've custom rendered. The only change to the code above is that I'm setting the field.Id so that the "if statement" at the lowest scope will evaluate render on the custom field. (otherwise it has the Id of the original "dummy" field)
        function updateField(model, id, value){      var $ = skuid.$;      var fModel = skuid.model.getModel(model);      var row = fModel.getFirstRow();      fModel.updateRow(row,id,value);        $.each(fModel.registeredLists,function(){         $.each(this.renderedItems,function(){            $.each(this.fields,function(){                if(this.id === id)                  this.render();            });        });     });  }    
  • Charlie JonasCharlie Jonas Member
    edited January 2014
    ahhhhh NVM I see. Because I'm using a custom renderer my snippet gets calls whenever I call this.render();. I was setting value = ''; when instead I needed to query the model for the value to use. It only took me about 20 minutes of stepping through the highly efficient (and hard to read) render() function to figure this out, haha
Sign In or Register to comment.