Undefined is not a function when calling node module

217 views Asked by At

I've separate some logic to different file in my project, the problem is that I got the following error

Cannot read property 'readFile' of undefined

this is the structure of my project

projName
   utils
     file.js

the file.js code is

module.exports = function () {
   var  fs = require('fs');
    function readFile(filePath) {
        fs.readFile(filePath, 'utf8', function (err, data) {
            if (err) {
                return console.log("error to read file:  " + filePath + " " + err);
            }
            return data;
        });
    }
};

I want to call to this module at

projname
    controller
         request

I do it with the following code And here I got the error

   module.exports = function (app) {
        app.get('/test', function(req, res) {

            var file = require('../utils/file')();
            var fileContent = file.readFile("C://test.txt");

any idea what am I doing wrong here? This is not related to async call

2

There are 2 answers

1
Wilson On BEST ANSWER

Your file.js could be like this:

var fs = require('fs');

module.exports.readFile = function (filePath, cb) {
  fs.readFile(filePath, 'utf8', cb);
};

and your request.js file like this:

var file = require('../utils/file');

module.exports = function (app) {

  var fileContent = '';
  var filePath = 'C://test.txt';

  file.readFile(filePath, function (err, data) {
    if (err) {
        return console.log("error to read file:  " + filePath + " " + err);
    }

    console.log(data);
    fileContent = data;
  }); 

  // some content

}

Regarding the async call when you call a method from Node.JS libaries, it is usually a async call, that means that the result of the function is not going to return immediately:

var data = fs.readFile(filePath);

instead it is going to return at some time later, so the only way you can get the results later is passing by a function that is going to be called when the results are ready:

fd.readFile(filePath, function dataReady (err, data) {
  console.log(data)
});

Regarding module.exports when you export some logic of a file that you created in Node.JS, you can return your function on the following ways:

// exporting a function, myModule.js
module.exports = function () { 
  console.log('hello');
};

// consuming myModule.js
var someFunction = require('./myModule.js');
someFunction(); // prints 'hello';

// exporting a function, myModule.js
module.exports.readFile = function () {
  console.log('hello');
};

// consuming myModule.js
var myModule = require('./myModule.js');
myModule.readFile(); // prints 'hello';

UPDATE: In your file.js you are exporting a function that is going to receive a file path and a function called callback as the second parameter (yes, you read it well, a function as a parameter) which is going to be called once the fs.readFile get the file content.

module.exports.readFile = function (filePath, callback) {
  fs.readFile(filePath, 'ut8', function (err, fileContent) {
    callback(err, fileContent);
  });
}

then in your request.js file, you are using your module (file.js) you just created, and the function that your module is exporting accepts a string as parameter called filePath, and a function as parameter called callback: file.readFile(filePath, callback)

so when your module file.js get the content file is going to call to your callback function parameter.

var file = require('../utils/file');

file.readFile(filePath, function (err, data) {
  if (err) {
    return console.log("error to read file:  " + filePath + " " + err);
  }

  console.log(data);
  fileContent = data;
});

I hope that this helps to clarify a little bit your knowledge about callbacks.

5
Scimonster On

You don't return anything in your module.exports function. In fact, you don't even need to set module.exports to a function. Just simply export your function:

var  fs = require('fs');
function readFile(filePath) {
    fs.readFile(filePath, 'utf8', function (err, data) {
        if (err) {
            return console.log("error to read file:  " + filePath + " " + err);
        }
        return data;
    });
}
exports.readFile = readFile;

Also, your return data isn't going to work, as fs.readFile is asynchronous. You need to use callbacks. So, your readFile function might look more like:

function readFile(filePath, callback) {
    fs.readFile(filePath, 'utf8', function (err, data) {
        if (err) {
            return console.log("error to read file:  " + filePath + " " + err);
        }
        callback(data);
    });
}