Miguel
Miguel

Reputation: 21

Using module.exports to return an object

I'm using csvtojson to parse a csv file and want to use it in another module in NodeJS. Pretty sure this is a noob issue in my attempt to learn NodeJS.

function loadPortfolio (portfolio) {
  //Converter Class 
  var Converter = require("./node_modules/csvtojson").Converter;
  var converter = new Converter({});

  //end_parsed will be emitted once parsing finished 
  converter.on("end_parsed", function (jsonArray) {
    var jsonText = JSON.stringify(jsonArray);
    var portfolioObj = JSON.parse(jsonText);

    module.exports = loadPortfolio;
  });

  //read from file 
  require("fs").createReadStream("./charlesriverexport.csv").pipe(converter);

};

Then in my app.js file:

var loadPortfolio = require('./loadPortfolio');

console.log("Portfolio: ", portfolio);

But, unfortunately the portfolio object comes as undefined.

Any ideas?

Thanks

Upvotes: 1

Views: 6118

Answers (2)

hammus
hammus

Reputation: 2612

You're not calling the loadPortfolio() function anywhere, you're using the wrong variable name in your app.js file and your module.exports can be moved to improve readability

The last part is optional but makes it easy to see whats exported at the top of every file as soon as you open it

NOTE: This only works if you use named function definitions: function myFunc() {} and NOT when you store the function in a variable i.e. let myFunc = function() {}.

Hoisting in JS allows to do this in your module file:

module.exports = loadPortfolio;
function loadPortfolio (portfolio) {
  //Converter Class 
  var Converter = require("./node_modules/csvtojson").Converter;
  var converter = new Converter({});

  //end_parsed will be emitted once parsing finished 
  converter.on("end_parsed", function (jsonArray) {
    var jsonText = JSON.stringify(jsonArray);
    var portfolioObj = JSON.parse(jsonText);


  });

  //read from file 
  require("fs").createReadStream("./charlesriverexport.csv").pipe(converter);

};

As functions get loaded before the module is executed, you can export before the function is defined.

then you need to call the function in app.js

var loadPortfolio = require('./loadPortfolio');
var portfolio = loadPortfolio();

console.log("Portfolio: ", portfolio);

Upvotes: 1

Daniel Lizik
Daniel Lizik

Reputation: 3144

Your exported module has to be a function that takes a callback as its parameter. The exported function will supply the callback with the data that is generated asynchronously.

var fs = require('fs');
var Converter = require('./node_modules/csvtojson').Converter;

module.exports = function loadPortfolio (callback) {

  var converter = new Converter({});

  fs.createReadStream('./charlesriverexport.csv').pipe(converter);

  converter.on('end_parsed', function (jsonArray) {
    var jsonText = JSON.stringify(jsonArray);
    var portfolioObj = JSON.parse(jsonText);
    callback(portfolioObj);
  });

};

And in the file where you use this module:

var loadPortfolio = require('./loadPortfolio');
loadPortfolio(function(portfolioObj) {
  console.log(typeof portfolioObj); // => 'object'
});

Edit: if you want to use the asynchronously fetched portfolioObj outside of the callback context of loadPortfolio you have to set an undefined variable then assign it within the callback.

//set undefined variable
var portfolio;

//import your function
require('./loadPortfolio')(function(portfolioObj) {

  //assign the global variable a value
  portfolio = portfolioObj;

  //when doSomething runs portfolio is guaranteed to be defined
  doSomething();
});

//see the problem with calling doSomething outside the callback?
doSomething(); // => 'undefined'

function doSomething() {
  console.log(typeof portfolio); // => 'object'
}

A neater way to do this is with promises, however.

Upvotes: 2

Related Questions