Frage

Just learning ember.js, and started building an app with ember-app-kit.

I am using the provided api-stub to stub out the api, but I decided to read in external json files to use as "fixture data". The reason for this decision - I will use the same json files to test both my ember app as well as the rails api back-end. Here's a gist with example of my json files.

So my api-stub/routes.js currently looks like this:

WORKING IMPLEMENTATION

var path = require('path');
var fs = require('fs');
// going to sibling directory
var fixtureDir = path.resolve(__dirname, '../..', 'lightfixtures')

module.exports = function (server) {

    // Create an API namespace, so that the root does not
    // have to be repeated for each end point.
    server.namespace('/api', function () {

      var locationsProtocol = JSON.parse(fs.readFileSync(fixtureDir + '/locations.json'));
      var roomsProtocol = JSON.parse(fs.readFileSync(fixtureDir + '/rooms.json'));

      // stub location list request
      server.get(locationsProtocol[0].request.url, function (req, res) {
        res.send(locationsProtocol[0].response.data);
      });

      // stub individual location request
      server.get(locationsProtocol[1].request.url, function (req, res) {
        res.send(locationsProtocol[1].response.data);
      });

      // stub room list request
      server.get(roomsProtocol[0].request.url, function (req, res) {
        res.send(roomsProtocol[0].response.data);
      });

      // stub individual room request
      server.get(roomsProtocol[1].request.url, function (req, res) {
        res.send(roomsProtocol[1].response.data);
      });
    });
  };

So, while reading the files and parsing parts of it for stubbing appropriate requests works fine - but looks very redundant. I would like to iterate over parsed json and generate stubs for all elements, to DRY it out and make it easy to add more stubs, something like this:

DESIRED IMPLEMENTATION

...
var locationsProtocol = JSON.parse(fs.readFileSync(fixtureDir + '/locations.json'));
var roomsProtocol =     JSON.parse(fs.readFileSync(fixtureDir + '/rooms.json'));

function respondToEach(json) {
  for (var i = 0; i < json.length; i++) {
    server.get(json[i].request.url, function (req, res) {
      res.send(json[i].response.data);
    });
  }
}

respondToEach(locationsProtocol);
respondToEach(roomsProtocol);
...

But it fails! Ember throws a default error, and in the network pane claims it gets an internal server error (500), and response section says "TypeError: Cannot read property 'response' of undefined" (line indicated is this one - res.send(json[i].response.data);

I'm confused - i think working implementation and "desired" implementation should yield the exact same output - but it's not the case. Can someone help me understand WHERE DID I FAIL (i.e. how the refactored version is different), and perhaps how I could remedy the problem?

War es hilfreich?

Lösung

You're running into the infamous javascript loop closure issue :) inside of each anonymous function i will end up being the length of json when evaluated.

Something like this should work

function respondToEach(json) {
  for (var i = 0; i < json.length; i++) {
    (function(idx){
      server.get(json[idx].request.url, function (req, res) {
        res.send(json[idx].response.data);
      });
    })(i);
  }
}

or you can define another function and that will fix the closure issue

function realResponse(item){
  server.get(item.request.url, function (req, res) {
    res.send(item.response.data);
  });
}

function respondToEach(json) {
  for (var i = 0; i < json.length; i++) {
    realResponse(json[i]);
  }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top