Forms

Forms typed from the form XML in JetBrains IDEs, with completion, navigation, dwfrm_ names, Find Usages, rename and checks for SFRA and SiteGenesis code

Intellij SFCC types every form from its XML in cartridge/forms, with no generated files. Fields, groups, lists and actions complete in scripts and templates, open in the XML with Cmd+Click and rename everywhere they are used

A form from server.forms.getForm is typed from its XML. Completion lists its fields with their type, label and cartridge, and Cmd+Click on a field opens it in the form, where each node shows its usages and each message key its text

Before you start

NeedsWhy
A valid license or trialTypes, completion, navigation, Find Usages, rename, dwfrm_ names, documentation and inspections are paid features. A license applies without a restart
Form XML in a linked cartridgeOnly files directly in cartridge/forms/<locale>/ count, see Which copy is used
Finished indexingForms come from the IDE index

XSD validation, highlighting and the RegExp injection in the form XML are free, see XML & JSON Validation

Where forms are typed

CodeFlavor
server.forms.getForm('newsletter')SFRA. Fields have typed values, base is the dw.web form, and toObject() and the keys of copyFrom({}) follow the XML
session.forms.newsletter, session.getForms().newsletter, pdict.CurrentForms.newsletterdw.web, in scripts and templates
app.getForm('newsletter.contact'), FormModel.get(...)SiteGenesis, with typed get, getValue, setValue and handleAction handlers

A form passed to res.render keeps its type in the template's pdict, see ISML scripting

var newsletterForm = server.forms.getForm('newsletter');
var email = newsletterForm.contact.email.value; // string
var optIn = newsletterForm.contact.optIn.value; // boolean

Which copy is used

The types come from one copy of the form, as B2C Commerce picks it

  • The first default copy on the site's cartridge path wins the whole file. Copies are never merged
  • Without a site scope, every linked cartridge counts, in the linked order. A copy in a cartridge that isn't on the path never wins
  • Locale copies such as forms/fr_FR/ don't change the types
  • <include> elements are expanded, so an included form's fields complete as members

Name a form's type

Three types name a form in JSDoc and TypeScript

TypeFor
SfraFormOf<'newsletter'>The SFRA form of server.forms.getForm
DwFormOf<'newsletter'>The dw.web form of session.forms
FormModelOf<'newsletter.contact'>The SiteGenesis form model of app.getForm
/** @param {SfraFormOf<'newsletter'>} form */
function subscribe(form) {
    return form.contact.email.value;
}

In a .ts file an unannotated require('server') is any, so annotate the form with SfraFormOf

Completion

WhereCompletes
getForm(''), app.getForm(''), session.forms.Form names, with the cartridge of the copy in use and +N locales
newsletterForm.contact.Fields, groups, lists and actions, before the base members such as valid and htmlName
app.getForm('newsletter.'), copyFrom({ }), handleAction({ })Paths and keys of the form

Each member shows the icon of its kind, the base type such as SfraFormFieldString, its label from the resource bundle and required, with the cartridge of the form on the right

ActionResult
Cmd+Click on a form name or memberOpens the element in the copy in use
Quick Documentation (F1, Ctrl+Q)The element's path, its dwfrm_ name, type, constraints, options and copies
Navigate › SymbolFinds form names, dotted paths and dwfrm_ names
Copy Reference in the form XMLCopies the dotted path, such as newsletter.contact.email
Copy HTML Name in the form XMLCopies the dwfrm_ name, such as dwfrm_newsletter_contact_email. It sits after Copy Reference in Copy Path/Reference

HTML names

dwfrm_ names complete, open the field with Cmd+Click and rename with it wherever they appear

dwfrm_ names complete in client scripts, jQuery selectors, templates and req.form, and Cmd+Click opens the field. In the form XML, Copy HTML Name copies the name of the element at the caret
  • Strings in scripts, client scripts in client/ and static/ included, and jQuery selectors such as $('#dwfrm_newsletter_contact_email')
  • ISML attributes, such as name="dwfrm_newsletter_contact_email"
  • req.form.dwfrm_newsletter_contact_email and request.httpParameterMap.dwfrm_newsletter_contact_email

A name that matches no form isn't marked as an error. The Hard-coded form HTML name inspection, off by default, suggests htmlName instead of a literal

Find Usages and rename

Find Usages (Option+F7, Alt+F7) on a form, a field in the XML or any member read groups the results by kind

GroupExample
Form name or pathgetForm('newsletter'), newsletterForm.contact.email
Form key in an object literalcopyFrom({ email: ... }), handleAction({ subscribe: ... })
Form element HTML name$('#dwfrm_newsletter_contact_email')
Form include<include formid="address" name="address"/>
Pipeline key bindingkey-binding alias="CurrentForms.newsletter"
Pipeline branchThe source-connector of an interaction-continue branch, for an action
List selection fieldselectone-fieldid and selectmany-fieldid of a list

Rename (Shift+F6) of a field, group or form updates every usage above. Rename copies in other cartridges and locales, on by default, renames the element in the other copies too. Names in _i0_ list items and names built at run time aren't found

In the form XML

FeatureWhat you see
UsagesN usages above each element, in the SFCC Forms group of Settings › Editor › Inlay Hints › Code vision
Message textThe text of each message key after it, the Form message text hint under Inlay Hints › Values
Message keyslabel, description, the *-error keys and form-error complete, open the .properties key and count as its usages
StructureThe Structure tool window lists the form's elements with their types
validationThe script is JavaScript with formfield declared
object-def, binding, attribute-defResolve to the system type and its attributes, custom attributes included, see Custom Attributes

Copies and locales

Gutter icons on a form link its copies: the copies it overrides on the cartridge path, the copies that override it and its locale copies. A locale copy that lacks an element of the default copy is reported, and the fix copies the element over

Gutter icons on the root element link the copies of a form. Each kind has its own switch under Settings › Editor › General › Gutter Icons

IconSwitchOpens
SFCC form overridesThe copies this one hides, further right on the cartridge path
SFCC form overridden byThe copies that hide this one
SFCC form locale copiesThe copies in other locale folders

Compare with Default Copy, Compare with Overridden Copy and Compare with Copy in Use open the two copies in the diff viewer. They are on the icons' right-click menu, the editor, editor tab and Project view menus, and Compare With

SiteGenesis handlers

In SiteGenesis code, handleAction checks its handlers against the form's actions. Add handler writes the missing one with the two parameters the runtime passes, and Cmd+Click on a handler opens its action

app.getForm('newsletter').handleAction({ ... }) checks its handlers against the form's actions. A handler for an action the form lacks never runs, and an action without a handler throws when it is triggered. Add handler writes the missing ones with the formGroup and action parameters, which are typed

Pipelines

In pipeline XML, key-binding alias="CurrentForms.newsletter.contact" resolves to the form and its elements, and the branches of an interaction-continue node to the actions of the form its template reads. Both complete, count as usages and rename with the form. Pipeline form bindings and branches that do not match the form reports a binding or branch the form lacks

Inspections

A form element that the XML doesn't declare is reported in scripts and templates. Add field writes it into the copy of the form that the types come from

Form checks are under Settings › Editor › Inspections › SFCC › Forms

InspectionGroupDefaultFixes
Unknown or cyclic form includeForm XMLErrorCreate form, Change to, remove a cyclic include
Duplicate or conflicting form elementsForm XMLErrorRename, remove the element or attribute, Change to
Field attribute with no effect for the field typeForm XMLWeak warningRemove the attribute
Form attribute missing from the schemaForm XMLWarningRemove the attribute
Locale copy that differs from the default copyForm XMLWarningCopy from the default copy, Open the default copy, Create the default copy from this one
Pipeline form bindings and branches that do not match the formPipelinesWarningChange to
Hard-coded form HTML nameScripts and templatesOffUse htmlName
Unknown formScripts and templatesWarningCreate form, Change to
Unknown form elementScripts and templatesWarningChange to, Add field
SiteGenesis handleAction handlers that do not match the form's actionsScripts and templatesWarningAdd handler, Remove handler, Change to
SFRA form lists read from the form objectScripts and templatesWeak warningUse form.base

Two more checks join the existing ones

  • An SFRA member the form lacks is reported by JavaScript's unresolved reference warning, as "No element 'phone' in 'newsletter.contact'", with Add field. options on a field without <options> reads "options is undefined at runtime"
  • <isinputfield formfield="${...}"> with a value that isn't a dw.web form field is reported by the ISML Attribute expression type mismatch inspection

Troubleshooting

ProblemFix
A form doesn't completeCheck that its XML is directly in cartridge/forms/default/ of a linked cartridge and that the license or trial is active
A member has the wrong typeAnother cartridge's copy wins. Quick Documentation on the form name lists its copies, and a site scope picks the cartridge path
An SFRA list has no membersRead it from form.base, as the SFRA form lists read from the form object fix does
No types in for eachfor each in a .js file isn't typed. for...of, and for each in .ds files and <isscript>, are
No types in a .ts fileAnnotate the form with SfraFormOf<'name'>

On this page