[Solved] Xml2js doesnt seem to work with Ionic 4 Beta with Angular 6

I have started to learn Angular 6/Ionic 4 beta and tried integrating xml2js package as following

I used the following commands

pm install @types/xml2js --save
npm install @types/xml2js --save-dev
npm install --save stream timers

However, when i run the project with the following import

import xml2js from 'xml2js';

then i get following error

node_modules/@types/xml2js/index"’ has no default export

So i then imported like this

import * as xml2js from 'xml2js';

I then created a service to use it and project compiles fine but service is undefined on runtime

Service Code

import { Injectable } from '@angular/core';
import * as xml2js from 'xml2js';

@Injectable({
  providedIn: 'root'
})
export class DataTransformService {


    constructor() {
    }

    public convertToJson(data: string): Object {


        console.log(data);
        console.log(xml2js);
        console.log(xml2js.parseString);

        let res;

        // setting the explicitArray option prevents an array structure
        // where every node/element is always wrapped inside an array
        // set it to true, and see for yourself what changes
        xml2js.parseString(data, { explicitArray: false }, (error, result) => {

            if (error) {
                throw new Error(error);
            } else {
                res = result;
            }

        });

        console.log(res);


        return res;

    }





}

HomePage.ts where im using it but get undefined service

import { Component } from '@angular/core';
import {DataTransformService} from '../services/data-transform.service';


@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {




    constructor(private dataTransformService: DataTransformService) {



    }



    fileChanged(e) {

        const file = e.target.files[0];
        console.log(file);


        const fileReader = new FileReader();

        fileReader.onload = this.onFileResponse;

        fileReader.readAsText(file);


    }





    private onFileResponse(e) {



        console.log(e);
        console.log(e.target.result);

        console.log(this.dataTransformService);


        this.dataTransformService.convertToJson(e.target.result);

    }



}

Please advise Thanks

this “only” install the type definition “for typescript” means you still need to install the library in your project

npm i xml2js --save

that might be the reason, if you didn’t did it yet, why nothing is found at runtime

Thanks for your reply,
i actually did that, but i did it again just to be sure and got following message.
Looks like i need other dependcies to install but dont know how.
Can you please guide.
Thanks

Nah I don’t think these warning as related.

So console.log(xml2js); print undefined right?

Thank you for being patient with me.

I think, i finally know the issue.

On my MainTS file 's constructor, console.log works and display the service

constructor(private dataTransformService: DataTransformService)
{

		console.log(dataTransformService); //works

}

However, when i get the file from the and access this service in fileload function, its undefined.

 <input type='file' (change)="fileChanged($event)">
	fileChanged(e)
	{

		const file = e.target.files[0];
		console.log(file);


		const fileReader = new FileReader();

		fileReader.onload = this.onFileResponse;

		fileReader.readAsText(file);


	}





	private onFileResponse(e)
	{


		console.log(e);
		console.log(e.target.result);

		console.log(this.dataTransformService);  //undefined here


		this.dataTransformService.convertToJson(e.target.result);

	}

Please advise about this undefined service in fileLoad handler
Once again, thanks

So it has absolutely nothing to do with the subject of your post and xml2js :wink:

maybe try

fileReader.onload = () => {
     console.log(this.dataTransformService);
};
1 Like

Thanks it worked

Can you please explain why a separate function didnt access TS class’s functions even though both are in that same class?

Honestly I’m not sure, I think it’s probably because doing so you declare a new function to the loader which will end up being another instance and therefore won’t have access to the private injected service…but I’m tired so I won’t be surprise if I say something wrong :wink:

anyhow cool if it worked out

The short answer is “because JavaScript is poorly designed”. The longer answer is in here: arrow functions inherit this from their point of definition, whereas when you assign onFileResponse as an ordinary function, its execution context (what this means) is at the whim of the point of call.

1 Like

Thanks guys

@rapropos
Just to confirm,
to handle such cases where i access not TypeScript api (like FileLoader) ill have to/must use Arrow functions? there is no way i can pass this to that secondary function except calling that secondary function in arrow and passing it this manually?

“No way” is too strong, but arrow functions are IMHO the cleanest and most readable way. You could do something like so:

let self = this;
thingyThatWantsCallback(function() {
  self.whatever;
});

…which is what happens, more or less, with arrow functions under the hood, but I find that harder to read and more error-prone.

1 Like

Thank you very much Sir