Angular fs.ReadFile cannot find the file with absolute path, nor can I compile the path with path.resolve

46 views Asked by At

I'm using my angular frontend to connect to a dymo labelprinter. The current setup, I have the entire xml file as a string inside an object. Than a parse it to json, let my code do changes based on the product, reconvert to xml and send it to the labelprinter.

I wanted to make this work better by moving my object containing a giant string with the xml, to a separate label.xml file. I'm having trouble with "finding" this file. To parse the file I am using xml2js. I'm trying to use the function described under the title 'Simple as pie usage' to read in the xml file. I copied the example below:

var fs = require('fs'),
xml2js = require('xml2js');

var parser = new xml2js.Parser();
fs.readFile(__dirname + '/foo.xml', function(err, data) {
    parser.parseString(data, function (err, result) {
        console.dir(result);
        console.log('Done');
    });
});

First I tried it with the absolute path, which as I understood it, should definitly work on my local machine. But I kept getting an error in the browser "unresolved promise - Cannot find file". If checked countless times that I wasn't making mistakes in the path. But this wasn't the issue. I found relevant topics on this matter on a similar function in fs.readFileSync().

When I understand these topics corrects, fs.readFile will not work with an absolute path, and it always needs relative path. But since it is in different working directory, I need to use path.resolve() to set up the right path.

I'm not 100% sure I'm using it right, but when I use the path.resolve(), the console gives an error when going over this line of code:path.resolve is not a function. This is the code going on to retrieve the label.xml file:

const path = require("path");
var fs = require('fs'),
xml2js = require('xml2js');

var parser = new xml2js.Parser();
  fs.readFile(path.resolve("src/assets", '../label.xml'), function(err: any, data: any) {
      parser.parseString(data, function (err: any, result: any) {
          console.dir(result);
          console.log('Done');
      });
  });

the absolute paths to my component and my label.xml are are:

  //absolute path to current ts file :  /c/Users/MyUsername/OneDrive/Documenten/Projects/ProjectName/src/app/components/componentName/componentName.ts
  //absolute path to label.xml file : '/c/Users/MyUsername/OneDrive/Documenten/Projects/ProjectName/src/assets/label.xml'

I would like to know why my angular is unable to use path.resolve(). I also went through a lot of documentation, but I don't know that fixing that function would solve the problem, because fs.ReadFile() also doesn't work with an absolute path. As stated I am not sure weather I'm correct that this functions needs a relative path to work. Can I get help on how to implement this function with my personal paths?

Maybe it is not due to the code, but there is a problem with the xml2js dependency? Beacuse I have to install it with --legacy-peer-deps. But I have this with a lot of dependencies because I'm using angular15 now. To be complete, I also added my package.json below. I don't think the issue has something to do with this.

{
  "name": "MyProjectName",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^15.0.1",
    "@angular/cdk": "^14.2.3",
    "@angular/common": "^15.0.1",
    "@angular/compiler": "^15.0.1",
    "@angular/core": "^15.0.1",
    "@angular/forms": "^15.0.1",
    "@angular/platform-browser": "^15.0.1",
    "@angular/platform-browser-dynamic": "^15.0.1",
    "@angular/router": "^15.0.1",
    "@fortawesome/angular-fontawesome": "^0.12.0",
    "@fortawesome/fontawesome-common-types": "^6.2.1",
    "@fortawesome/fontawesome-svg-core": "^6.2.1",
    "@fortawesome/free-brands-svg-icons": "^6.2.1",
    "@fortawesome/free-regular-svg-icons": "^6.2.1",
    "@fortawesome/free-solid-svg-icons": "^6.2.1",
    "@ng-bootstrap/ng-bootstrap": "^14.0.0",
    "@ng-select/ng-select": "^9.0.2",
    "@popperjs/core": "^2.11.6",
    "@types/dymo-label-framework": "^1.2.36",
    "bootstrap": "^5.2.1",
    "express": "^4.18.2",
    "file-saver": "^2.0.5",
    "fs-web": "^1.0.1",
    "mdb-angular-ui-kit": "^3.0.0",
    "rxjs": "~7.5.0",
    "stream": "^0.0.2",
    "timers": "^0.1.1",
    "tslib": "^2.3.0",
    "url": "^0.11.3",
    "xml2js": "^0.6.2",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^15.0.2",
    "@angular/cli": "~15.0.2",
    "@angular/compiler-cli": "^15.0.1",
    "@angular/localize": "^15.0.1",
    "@types/file-saver": "^2.0.5",
    "@types/jasmine": "~4.0.0",
    "@types/node": "^20.11.5",
    "jasmine-core": "~4.1.0",
    "karma": "~6.3.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.0.0",
    "karma-jasmine-html-reporter": "~1.7.0",
    "typescript": "~4.8.4"
  }
}
2

There are 2 answers

1
NgDaddy On

Do you try to use this:

const path = require("path");
var fs = require('fs'),

in a browser?

0
Yannick Mussche On

One part of the question has been answered by V.S. that it is not possible to use/test path on the browser. The link he provides is angular 8 and it does not work anymore for Angular 14. But I found a way to make it work in Angular 14.

First I managed to get the result by subscribing it, like this:

getXmlFile(){
return this.http.get("/assets/label.xml", {responseType : "text"});
 }

this.getXmlFile().subscribe((data: any)=>{
      let parseString = require('xml2js').parseString;
      parseString(data, (err: any,result: any) =>{
        this.labelJson = result;
    });
});

But since I need the data in a variable for action. I made the function async.

async getXmlFileASync(){
    const responseObservable = this.http.get("/assets/label.xml", {responseType : "text"});
    return await firstValueFrom(responseObservable);
  }

const labelXml = await getXmlFileASync();

parseString(labelXml , (err: any,result: any) =>{
    console.log(result);
});

You could also make the parseString asynchronous if you would need it in a variable, because if you would insert it in an object directly, the object would be empty. I don't need that in this case.