Example of using XmlLoader(parentClass) in TypeScript

I am using the BABYLON.GUI.XmlLoader to load my GUI in TypeScript and I want to connect it to a class but whatever I put in the constructor

  const xmlLoader = new BABYLON.GUI.XmlLoader(this);

I get an error in Typescript. Any suggestions?

Argument of type ‘this’ is not assignable to parameter of type ‘null’.
Type ‘myclass’ is not assignable to type ‘null’.ts(234

That’s due to a modern way of typescript, using the default value to set the type of the element. So this:

constructor(parentClass = null) {

will make typescript assume that parentClass can only be null. The simple solution would be:

constructor(parentClass: any = null) {

Have you tried passing something as any?

We’ll need to fix it on our side for sure. if you want to PR this, please do :slight_smile:

@msDestiny14 would be great if it could be typed here ?

I was able to get it to call a function in the class with this syntax:

const loader = new BABYLON.GUI.XmlLoader(<any>this);

where I have onPointerClickObservable=“onclick” attributes in the xml.
the function in the class get called by the “this” in the onclick is not the instance I passed into the XmlLoader function. Is there an example of how this should work?

onclick(){

}

You might want to check with @msDestiny14 how she is serializing / deserializing as I am guessing it is now full JSON based and I wonder if the xmlLoader version is uptodate @Deltakosh ?

The xmlloader is a community initiative (on my phone right now but we should look on the forum or on GitHub to find the initial author)

The serialization for the GUI is JSON I believe.

yes it is

but xmlLoader is from @Null / Null0924 (Null) (github.com)

doc: XML Loader | Babylon.js Documentation (babylonjs.com)

Yup let s see if @Null an update the loader ? @Michael_Scherotter It is probably safer to move to the JSON serialization in the meantime

1 Like

Hey there,

Sorry, just saw this. Yes, I recently run to the same “this” type of null issue. I will change it and make a PR. For now, just cast it as any like you are already doing.

I haven’t fully tested it with TypeScript but I would assume it should work just fine. What is the “this” you are passing? Is it inside a callback? If yes you have to use the fat arrow syntax " () => { }" or to bind the “this” in the callback otherwise “this” will refer to the function instead of the class.

I will either way run a test and see if this is working or not and let you know.

Okay so I just tested with a regular class method and it works. This binds correctly as expected. I will commit a PR for the constructor parameter, the rest seems to be working correctly. If you find any other issue @Michael_Scherotter let me know.

@sebavan Besides a few TypeScript semantics, I would expect the XML loader to work just fine. XML is just much more readable than JSON imho.

Can you please share the example that works just fine because it isn’t working as expected for me.
Thanks,
Michael

The example is the same as in the documentation. It should work out of the box. Perhaps, if you share what you are doing we might be able to spot what’s wrong. I have a good feeling you are initiating it inside a callback thus losing the class reference.

1 Like

In my xml gui code, I have an Button with this attribute: onPointerClickObservable="onFullScreenPressedAsync"

export class MyGui{
    _scene: BABYLON.Scene;

    constructor(gui: BABYLON.GUI.AdvancedDynamicTexture, scene: BABYLON.Scene){
        this._scene = scene;

        const xmlLoader = new BABYLON.GUI.XmlLoader(<any>this);

        xmlLoader.loadLayout(`/api/gui.xml?backButton=${!foyer}`, gui, ()=>{
        });
    }

    async onFullScreenPressedAsync(arg1:any, arg2:any){
    // "this" is not an instance of the MyGui class
    }

Hmm, I am not sure but I think this has something to do with the callback being async. Could you try without it being async and let me know? I’ll run a few tests later with this setup as well.

Actually, now that I think of it, the method being called as a callback, can’t have this as a reference. You have to use the fat arrow syntax.


onFullScreenPressedAsync = (arg1:any, arg2:any) =>{

Should work.

How do I specify that onFullScreenPressedAsync is a member of the typescript class?

constructor(gui: BABYLON.GUI.AdvancedDynamicTexture, foyer: boolean, scene: BABYLON.Scene, guide: Guide, galleryInfo: GalleryInfo){
        this._scene = scene;
        this._guide = guide;
        this._galleryInfo = galleryInfo;

        const xmlLoader = new BABYLON.GUI.XmlLoader(<any>this);

        xmlLoader.loadLayout(`/api/gui.xml?backButton=${!foyer}`, gui, ()=>{

            this._guiLoader = xmlLoader;
        });

        this.onFullScreenPressedAsync = (arg1:any, arg2:any)=>{
            this.onFullScreenPressed(arg1, arg2);
        };
    }

causes a TypeScript Error :
Property ‘onFullScreenPressedAsync’ does not exist on type ‘Gui’.ts(2339)



export class MyGui{
    _scene: BABYLON.Scene;

    constructor(gui: BABYLON.GUI.AdvancedDynamicTexture, scene: BABYLON.Scene){
        this._scene = scene;

        const xmlLoader = new BABYLON.GUI.XmlLoader(<any>this);

        xmlLoader.loadLayout(`/api/gui.xml?backButton=${!foyer}`, gui, ()=>{
        });
    }

    async onFullScreenPressedAsync = (arg1:any, arg2:any) => {
    // "this" is not an instance of the MyGui class
    }

This should work as intended

1 Like

One minor modification → placement of async

onFullScreenPressedAsync = async (arg1:any, arg2:any) => {
  "this" is now correct
}

Yes, that’s correct, async should be there. I assume it worked right? Btw, this is javascript limitations and. Not related to the loader.

1 Like