I'm curious to hear peoples thoughts on the below....
# suitescript
m
I'm curious to hear peoples thoughts on the below. Working with N/ui/serverWidget, I find it pretty annoying when creating fields that some of the configuration is passed in the addField method, some of it is object setters, and then there are update methods as well for things like display type.
Copy code
const field = form.addField({
  id: "custpage_my_field",
  label: "Field Label",
  type: ui.FieldType.TEXT,
});

field.isMandatory = true;
field.defaultValue = "Hello";
field.helpText = "Help Text Here";

field.updateDisplayType({ displayType: ui.FieldDisplayType.INLINE });
I've written a simple wrapper around addField that accepts a single parameter for everything (code in thread)
Copy code
addField(form, {
  id: "custpage_my_field",
  label: "Field Label",
  type: ui.FieldType.TEXT,
  isMandatory: true,
  defaultValue: "Hello",
  helpText: "Help Text Here",
  displayType: ui.FieldDisplayType.INLINE,
});
Would love to hear if anyone else has this same gripe and if you think this is approach lends to cleaner/clearer code or you would find it more confusing?
Copy code
function addField(formOrSublist, options) {
    const validFieldOptions = ["id", "label", "type", "source", "container"];

    const validFieldProperties = [
      "isMandatory",
      "helpText",
      "defaultValue",
      "linkText",
      "maxLength",
      "richTextHeight",
      "richTextHeight",
      "padding",
    ];

    const validUpdateMethods = ["breakType", "displaySize", "displayType", "layoutType"];

    const fieldOptions = pick(options, validFieldOptions);
    const fieldProperties = pick(options, validFieldProperties);
    const updateMethods = pick(options, validUpdateMethods);

    const field = formOrSublist.addField(fieldOptions);

    for (const [key, value] of Object.entries(fieldProperties)) {
      field[key] = value;
    }

    for (const [key, value] of Object.entries(updateMethods)) {
      const updateMethodName = `update${key.charAt(0).toUpperCase()}${key.slice(1)}`;
      const options = typeof value === "object" ? value : { [key]: value };
      field[updateMethodName](options);
    }

    if (options.hasOwnProperty("selectOptions")) {
      options.selectOptions.forEach((selectOption) => field.addSelectOption(selectOption));
    }

    return field;
  }
👍 1
b
very similar to what i have actually
m
😄 guess I'm on the right track then, thanks
b
in a rare case of me actually sharing what my code looks like (its from my wasted time learning how assistants work)
🤩 1
looking at your code, you have a bug that i used to have
m
nice, thanks for sharing. what's the bug?
b
line 122 is where my addField begins
m
do you mean the defaultValue part?
b
yup
m
ahh i was using it like this, so wouldn't set defaultValue together with selectOptions
Copy code
{
	label: "Amount Remaining Operator",
	id: "custpage_amount_remaining_op_filter",
	type: ui.FieldType.SELECT,
	container: "custpage_search_filters",
	selectOptions: [
	  { value: "lessThan", text: "< (Less Than)", isSelected: true },
	  { value: "equalTo", text: "= (Equal To)" },
	  { value: "greaterThan", text: "> (Greater Than)" },
	],
	helpText:
	  "If you are filtering by Amount Remaining, select if the filter should look for values less than, more than or equal to the amount entered in that field",
}
i.e use
isSelected
for select options instead of
defaultValue
b
eventually i settled upon the standard no strings in code
Copy code
var restrictToScriptIdField = serverWidgetUtil.addField(
  restrictToScriptIdsSublist,
  _.assign(
    {
      type: serverWidget.FieldType.SELECT,
      source: "-417", // TODO find a better id for Script
      isMandatory: true,
    },
    fields.restrictToScriptId
  )
);
where fields.restrictToScriptId came from a metadata file
Copy code
{
  id: "custpage_restrict_to_script_ids",
  label: "Restrict to Script Ids",
  helpText: "Select the scripts that are allowed to use the GUID.",
}
m
yeah i do plan to move the strings out of the code, still in prototyping stage atm
j
I also have this gripe, BTW. Consistency would be nice, wouldn’t it? I always forget which are fn()s and which are params.
s
I presume that API is a result of java-isms on the backend. I don't use `serverWidget`often enough to justify writing (and debugging, and unit testing) helpers like the above myself.
With typescript definitions, I wouldn't mind the 'which is a property, which is a method' because that's all made entirely clear by the type definitions - you can't get it work in (ts) code.
s
I have a lib that takes all the form elements- groups, fields, tabs, sublists, submit button, client script- as an object and does all the building calls on it for the exact same reason
s
all this workaround is more evidence to do SPA like apps rather than 'native' suitelets