Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Be Able To Define Custom Interface Definition Creation #44

Closed
daryllabar opened this issue Dec 14, 2017 · 6 comments
Closed

Be Able To Define Custom Interface Definition Creation #44

daryllabar opened this issue Dec 14, 2017 · 6 comments

Comments

@daryllabar
Copy link

Null Safe Code like this is really annoying

var att = Xrm.Page.getAttribute("name");
if(att){
    att.setValue("someValue");
}

Which is why I've seen lots of people creator nullsafe helper functions:

MyLibrary.setValue("name", "someValue");

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?

@henrikhannemose
Copy link
Collaborator

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:

XrmDefinitelyTyped form .d.ts

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?

@daryllabar
Copy link
Author

True point, here is a couple counters.

  1. Many times I'll have very similar forms, and want to have a single JS file to handle all the forms. This could require multiple casts in order to get the form that has that particular field.
  2. 98% of the time, when I'm dealing with a lookup value, I don't want it in array form, I just want the selected item, in the array, so a typed helper function that returns back the entity reference rather than the array is nice.
  3. 98% of the time, when I'm dealing with control calls (set visible for example) I want to perform that action on every control for that attribute, so again a helper function that is typed to that would be helpful.
  4. As a contractor, I generally have very little control over what the client does with the forms when I'm gone. I'm not going to trust that they will regenerate the types and fix the JS files, so I would prefer to not fully trust the typings...
  5. I also provide overload helper function that accept a parameter to fire the on change event, so again, being able to have those helper functions typed, would be great...

@magesoe
Copy link
Collaborator

magesoe commented Dec 15, 2017

  1. XDT supports form intersections, which solves this problem. This is shown in our wiki

  2. 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.

  3. 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.

  1. 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.

  2. You can make a function that takes an XrmAttribute as well as the onChange function.

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.

@daryllabar
Copy link
Author

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.

@mktange
Copy link
Collaborator

mktange commented Dec 18, 2017

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

@magesoe
Copy link
Collaborator

magesoe commented Feb 28, 2018

Fixed in 53fc582

magesoe added a commit that referenced this issue Mar 2, 2018
@magesoe magesoe closed this as completed Mar 14, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants