@xrmforge/devkit 0.7.5 → 0.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -65,28 +65,40 @@ export const onLoad = wrapHandler('LM.Account.onLoad', logger, (ctx) => {
65
65
  const form = typedForm<AccountLMFirmaForm>(ctx.getFormContext());
66
66
 
67
67
  // Direct field access - fully typed, IDE autocomplete works
68
- const name = form.name.getValue(); // string | null (non-nullable, field is on form)
68
+ const name = form.name.getValue(); // string | null
69
69
  form.revenue.setValue(150000); // NumberAttribute
70
70
  const parent = form.parentaccountid.getValue(); // LookupValue[] | null
71
71
 
72
- // Control access
73
- form.$control('name').setDisabled(true);
72
+ // addOnChange directly on the proxy (NOT via $context.getAttribute)
73
+ form.name.addOnChange(() => { logger.debug('Name changed'); });
74
+ form.revenue.addOnChange(() => { recalculate(form); });
74
75
 
75
- // Full FormContext for ui, data, tabs, addOnChange
76
+ // Control access via controls proxy (typed from ControlMap, no cast needed)
77
+ form.controls.name.setDisabled(true);
78
+ form.controls.customerid.setEntityTypes([EntityNames.Account]); // LookupControl
79
+ form.controls.revenue.setVisible(false); // NumberControl
80
+
81
+ // Full FormContext for ui, data, tabs
76
82
  form.$context.ui.setFormNotification('OK', FormNotificationLevel.Info, 'id');
77
- form.$context.getAttribute(Fields.Name).addOnChange(() => { ... });
78
83
  });
79
84
  ```
80
85
 
81
- **When to use `form.$context.getAttribute(Fields.X)` instead of `form.fieldname`:**
82
- - `addOnChange()`, `removeOnChange()` (event registration on the attribute)
86
+ **Use `form.fieldname` (the typedForm proxy) for EVERYTHING on the attribute:**
87
+ - `getValue()`, `setValue()` (reading and writing values)
88
+ - `addOnChange()`, `removeOnChange()` (event registration)
83
89
  - `setRequiredLevel()`, `setSubmitMode()` (attribute-level settings)
84
- - `getControl()` with typed control access (use `form.$control(Fields.X)`)
90
+ - Any attribute method: the proxy returns the full typed Attribute object
85
91
 
86
- **When to use `form.fieldname` (the typedForm proxy):**
87
- - `getValue()`, `setValue()` (reading and writing values)
88
- - `addOnChange()` (event registration directly on the attribute)
89
- - Any read-only access to field values
92
+ **Use `form.controls.fieldname` for control-level operations:**
93
+ - `setDisabled()`, `setVisible()`, `setLabel()`
94
+ - `addPreSearch()` (on LookupControl)
95
+ - `setNotification()`, `clearNotification()`
96
+
97
+ **Use `form.$context` ONLY for FormContext-level operations:**
98
+ - `form.$context.ui` (setFormNotification, tabs, close)
99
+ - `form.$context.data` (save, entity, process)
100
+ - `form.$context.ui.getFormType()`
101
+ - NOT for getAttribute (use the proxy instead)
90
102
 
91
103
  **When to use `form.$unsafe(EntityFields.X)` (off-form fields):**
92
104
 
@@ -302,7 +314,7 @@ import { SaveMode, FormNotificationLevel, RequiredLevel, SubmitMode, DisplayStat
302
314
  if (ctx.getEventArgs().getSaveMode() === SaveMode.AutoSave) { ... } // not === 70
303
315
 
304
316
  // Form type (const enum from @types/xrm, works at runtime):
305
- if (form.$context.ui.getFormType() === XrmEnum.FormType.Create) { ... } // not === 1
317
+ if (form.$context.ui.getFormType() === FormType.Create) { ... } // not === 1
306
318
 
307
319
  // Display state:
308
320
  if (tab.getDisplayState() === DisplayState.Expanded) { ... } // not === 'expanded'
@@ -345,7 +357,8 @@ Xrm.Navigation.openForm({ entityName: EntityNames.Account, entityId: id }); //
345
357
  - Never magic numbers for OptionSet values, status codes, or FetchXML `<value>` (use OptionSet Enums)
346
358
  - Never magic numbers for time calculations (use named constants like `MS_PER_DAY`)
347
359
  - Never `getSaveMode() === 70` (use `SaveMode.AutoSave` from @xrmforge/helpers)
348
- - Never `getFormType() === 1` (use `XrmEnum.FormType.Create`)
360
+ - Never `getFormType() === 1` (use `FormType.Create` from `@xrmforge/helpers`)
361
+ - Never `XrmEnum.FormType` (does NOT exist at runtime, esbuild does not resolve const enums from .d.ts. Use `FormType` from `@xrmforge/helpers`)
349
362
  - Never `'expanded'`/`'collapsed'` (use `DisplayState` from @xrmforge/helpers)
350
363
  - Never `'ERROR'`/`'INFO'`/`'WARNING'` (use `FormNotificationLevel`)
351
364
  - Never `'none'`/`'required'`/`'recommended'` (use `RequiredLevel`)
@@ -367,6 +380,7 @@ Xrm.Navigation.openForm({ entityName: EntityNames.Account, entityId: id }); //
367
380
  - Never unlokalized UI strings (use `pickLang()` from constants.ts)
368
381
  - Never build your own getValue/setFieldValue/setDisabled/addOnChange helpers (use `typedForm` + native Xrm API)
369
382
  - Never `import ... from '@xrmforge/typegen'` in browser code (use `@xrmforge/helpers`)
383
+ - Never `as Xrm.Controls.LookupControl` or similar control casts (`form.controls.fieldname` returns the typed control from ControlMap)
370
384
  - Never `as any` without eslint-disable comment explaining why
371
385
  - Never untyped `catch (error)` (always `catch (error: unknown)`)
372
386
 
@@ -546,7 +560,7 @@ each attribute to its control. `mock.getControl(Fields.Name)` works out of the b
546
560
  | Legacy Pattern | XrmForge Replacement |
547
561
  |---|---|
548
562
  | `getAttribute("name")` | `form.name` (via typedForm) |
549
- | `getControl("name")` | `form.$control(Fields.Name)` |
563
+ | `getControl("name")` | `form.controls.name` |
550
564
  | `Xrm.Page.getAttribute(...)` | `form.fieldname` (via typedForm) |
551
565
  | `var formContext` (global) | `const form = typedForm<MyForm>(ctx.getFormContext())` |
552
566
  | `function form_OnLoad(ctx)` | `export const onLoad = wrapHandler(...)` |
@@ -568,11 +582,11 @@ Never recreate them. Use the typed API directly.
568
582
  |---|---|
569
583
  | `GetValue(fieldName)` | `form.fieldname.getValue()` (typed via typedForm) |
570
584
  | `SetValue(fieldName, value)` | `form.fieldname.setValue(value)` (typed via typedForm) |
571
- | `SetDisabled(attributeName, disabled)` | `form.$control(Fields.X).setDisabled(disabled)` |
572
- | `SetVisible(attributeName, visible)` | `form.$control(Fields.X).setVisible(visible)` |
585
+ | `SetDisabled(attributeName, disabled)` | `form.controls.fieldname.setDisabled(disabled)` |
586
+ | `SetVisible(attributeName, visible)` | `form.controls.fieldname.setVisible(visible)` |
573
587
  | `SetRequiredLevel(attributeName, level)` | `form.$context.getAttribute(Fields.X).setRequiredLevel(RequiredLevel.Required)` |
574
588
  | `AddOnChange(attributeName, callback)` | `form.$context.getAttribute(Fields.X).addOnChange(cb)` |
575
- | `AddPreSearch(controlName, callback)` | `(form.$control(Fields.X) as Xrm.Controls.LookupControl).addPreSearch(cb)` |
589
+ | `AddPreSearch(controlName, callback)` | `form.controls.fieldname.addPreSearch(cb)` (typed as LookupControl from ControlMap) |
576
590
  | `GetLookupValueId(fieldName)` | `formLookupId(form.fieldname)` |
577
591
  | `SetLookupValue(field, id, type, name)` | `form.fieldname.setValue([{ id, entityType, name }])` |
578
592
  | `GetId()` | `form.$context.data.entity.getId()` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xrmforge/devkit",
3
- "version": "0.7.5",
3
+ "version": "0.7.7",
4
4
  "description": "Build orchestration and project tooling for Dynamics 365 WebResources",
5
5
  "keywords": [
6
6
  "dynamics-365",