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
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 textBefore you start
| Needs | Why |
|---|---|
| A valid license or trial | Types, completion, navigation, Find Usages, rename, dwfrm_ names, documentation and inspections are paid features. A license applies without a restart |
| Form XML in a linked cartridge | Only files directly in cartridge/forms/<locale>/ count, see Which copy is used |
| Finished indexing | Forms 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
| Code | Flavor |
|---|---|
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.newsletter | dw.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; // booleanWhich copy is used
The types come from one copy of the form, as B2C Commerce picks it
- The first
defaultcopy 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
| Type | For |
|---|---|
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
| Where | Completes |
|---|---|
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
Navigation and documentation
| Action | Result |
|---|---|
Cmd+Click on a form name or member | Opens 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 › Symbol | Finds form names, dotted paths and dwfrm_ names |
| Copy Reference in the form XML | Copies the dotted path, such as newsletter.contact.email |
| Copy HTML Name in the form XML | Copies 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/andstatic/included, and jQuery selectors such as$('#dwfrm_newsletter_contact_email') - ISML attributes, such as
name="dwfrm_newsletter_contact_email" req.form.dwfrm_newsletter_contact_emailandrequest.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
| Group | Example |
|---|---|
| Form name or path | getForm('newsletter'), newsletterForm.contact.email |
| Form key in an object literal | copyFrom({ email: ... }), handleAction({ subscribe: ... }) |
| Form element HTML name | $('#dwfrm_newsletter_contact_email') |
| Form include | <include formid="address" name="address"/> |
| Pipeline key binding | key-binding alias="CurrentForms.newsletter" |
| Pipeline branch | The source-connector of an interaction-continue branch, for an action |
| List selection field | selectone-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
| Feature | What you see |
|---|---|
| Usages | N usages above each element, in the SFCC Forms group of Settings › Editor › Inlay Hints › Code vision |
| Message text | The text of each message key after it, the Form message text hint under Inlay Hints › Values |
| Message keys | label, description, the *-error keys and form-error complete, open the .properties key and count as its usages |
| Structure | The Structure tool window lists the form's elements with their types |
validation | The script is JavaScript with formfield declared |
object-def, binding, attribute-def | Resolve to the system type and its attributes, custom attributes included, see Custom Attributes |
Copies and locales
Gutter icons on the root element link the copies of a form. Each kind has its own switch under Settings › Editor › General › Gutter Icons
| Icon | Switch | Opens |
|---|---|---|
| SFCC form overrides | The copies this one hides, further right on the cartridge path | |
| SFCC form overridden by | The copies that hide this one | |
| SFCC form locale copies | The 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
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 actionapp.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
Form checks are under Settings › Editor › Inspections › SFCC › Forms
| Inspection | Group | Default | Fixes |
|---|---|---|---|
| Unknown or cyclic form include | Form XML | Error | Create form, Change to, remove a cyclic include |
| Duplicate or conflicting form elements | Form XML | Error | Rename, remove the element or attribute, Change to |
| Field attribute with no effect for the field type | Form XML | Weak warning | Remove the attribute |
| Form attribute missing from the schema | Form XML | Warning | Remove the attribute |
| Locale copy that differs from the default copy | Form XML | Warning | Copy 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 form | Pipelines | Warning | Change to |
| Hard-coded form HTML name | Scripts and templates | Off | Use htmlName |
| Unknown form | Scripts and templates | Warning | Create form, Change to |
| Unknown form element | Scripts and templates | Warning | Change to, Add field |
| SiteGenesis handleAction handlers that do not match the form's actions | Scripts and templates | Warning | Add handler, Remove handler, Change to |
| SFRA form lists read from the form object | Scripts and templates | Weak warning | Use 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.
optionson 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
| Problem | Fix |
|---|---|
| A form doesn't complete | Check 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 type | Another 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 members | Read it from form.base, as the SFRA form lists read from the form object fix does |
No types in for each | for each in a .js file isn't typed. for...of, and for each in .ds files and <isscript>, are |
No types in a .ts file | Annotate the form with SfraFormOf<'name'> |