Closed daryllabar closed 6 years ago
With XrmDefinitelyTyped we generate typings (i.e. a .d.ts file) for each form. There is thus no need to explicitly check if a field is on the form, since e.g. Xrm.Page.getAttribute("name")
is only valid if you have an attribute called name
on the given form:
This should eliminate the need for explicitly checking if a field is on the form, since we already know it is.
In theory the field could still have been removed from the form since the last time you generated the typings with XrmDefinitelyTyped. We eliminate any possible errors by ensuring that we run XrmDefinitelyTyped and build our VS solution as part of our deployment pipeline.
Do you see any other use cases for creating custom interface definitions in XrmDefinitelyTyped?
True point, here is a couple counters.
XDT supports form intersections, which solves this problem. This is shown in our wiki
We solve this issue by simply taking the first element of the array, but we agree that the behavior of always having entityreferences as an array is undesirable. We are currently discussing a better way of handling entityreferences as a whole.
You can make a function that takes an XrmAttribute and the function you want to apply to each control.
export function ForAllControls<T>(attr: Xrm.Attribute<T>, f: (c: Xrm.Control<Xrm.Attribute<T>>) => any) {
attr.controls.forEach(x => f(x));
}
ForAllControls(Page.getAttribute("accountnumber"), x => x.setDisabled(true));
This way you piggyback on the typings of XDT, such that you don't have to define the methods that are available on a control.
4. If you can't trust your typings, then you can't trust your typescript. We would advice you to setup a daily typings check of some kind, which could be done on a CI server. As @henrikhannemose mentioned, this is part of our deployment pipeline, but we also do a daily typings check.
5. You can make a function that takes an XrmAttribute as well as the onChange function.
```typescript
export function AddAndFire<T>(attr: Xrm.Attribute<T>, onChange: (c: Xrm.ExecutionContext<Xrm.Attribute<T>> | undefined) => any) {
attr.addOnChange(onChange);
attr.fireOnChange();
}
AddAndFire(Page.getAttribute("accountnumber"), fooChange);
As a general comment, we see the potential for allowing injection of interfaces like
declare namespace MyLibrary {
function setValue(attrName: "name", value: string);
function setValue(attrName: "phonenumber", value: number);
function setValue(attrName: "somedate", value: Date);
}
But for different use cases than the ones you described.
I was not aware of 1. Thanks for pointing it out.
2, 3, and 5 are all workarounds that I'm not particularly excited about, but definitely aren't bad either.
Thanks for the through explanation and examples.
Got an idea over the weekend that I believe solves this, and it should also be quite simple to implement in XDT.
Basically, XDT just needs to generate an interface for each collection (attributes, controls, etc) for all form, that maps the key of the object to the wanted type. The custom library should be defined to utilize these interfaces, by using keyof
and then applying the given key to get the correctly typed value.
In a form-script, the developer just has to declare the library to be of the wanted form-type (pretty much like you would do with Xrm.Page
).
Here is a gist with an example:
https://gist.github.com/mktange/4878da0477dc1244a273af7359ec10b2
Fixed in 53fc5821385b4749e64b971c4dde316e9c2a2dec
Null Safe Code like this is really annoying
Which is why I've seen lots of people creator nullsafe helper functions:
These functions may log if the attribute isn't on the form, but it won't throw a null ref exception.
Is there a way to get the generated d.ts files, to create interface definitions for these custom library calls?