-3

I have a rest service on the other end of the url in my code below that returns the names of all of the objects in an s3 bucket. I'm trying to create a simple Alexa skill that tells me how many objects are in that bucket. My problem is that within the http get request the term "this" is not referencing the same thing as it is outside of the http get request. How can I use "this" inside the get request or return the "count" variable from my http get request?

"use strict";
var Alexa = require("alexa-sdk");
var Client = require('node-rest-client').Client;

exports.handler = function(event, context, callback) {
    var alexa = Alexa.handler(event, context);
    alexa.registerHandlers(handlers);
    alexa.execute();
};

var handlers = {
    'Launch Request': function() {
        this.emit('CountItems');
    },
    'ContentsIntent': function() {
        this.emit('CountItems');
    },
    'CountItems': function() {
        var client = new Client();
        var count = undefined;
        client.get("URL", function (data, response) {
            console.log(data['Keys'].length);
            count = data['Keys'].length;
        });
        this.emit(':tell', 'There are ' + count + ' items in your s3 bucket.');
    }
};
Chris Bell
  • 51
  • 1
  • 6
  • 1
    Possible duplicate of [How to access the correct \`this\` inside a callback?](http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – Pineda Apr 15 '17 at 23:28

2 Answers2

1

It depends upon what you want the this value to be. If you want it to be the value it was right before the client.get() call then, the usual way (pre ES6) would be to just save its value into a local variable before the client.get() and then reference that saved value instead of this. In addition, the only place you can use the count is inside the callback so you have to put the .emit() in there too:

var handlers = {
    'Launch Request': function() {
        this.emit('CountItems');
    },
    'ContentsIntent': function() {
        this.emit('CountItems');
    },
    'CountItems': function() {
        var client = new Client();
        var self = this;
        client.get("URL", function (data, response) {
            let count = data['Keys'].length;  
            self.emit(':tell', 'There are ' + count + ' items in your s3 bucket.');
        });
    }
};

You can also use .bind():

var handlers = {
    'Launch Request': function() {
        this.emit('CountItems');
    },
    'ContentsIntent': function() {
        this.emit('CountItems');
    },
    'CountItems': function() {
        var client = new Client();
        client.get("URL", function (data, response) {
            let count = data['Keys'].length;  
            this.emit(':tell', 'There are ' + count + ' items in your s3 bucket.');
        }.bind(this));
    }
};

In ES6 (modern versions of node.js), you can define your callback with an arrow function and that will use the lexical value of this inside the callback:

var handlers = {
    'Launch Request': function() {
        this.emit('CountItems');
    },
    'ContentsIntent': function() {
        this.emit('CountItems');
    },
    'CountItems': function() {
        var client = new Client();
        client.get("URL", (data, response) => {
            let count = data['Keys'].length;  
            this.emit(':tell', 'There are ' + count + ' items in your s3 bucket.');
        });
    }
};

In an ES6 environment, most people find the arrow function to be the cleanest way of doing things.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
0

The variable count should be available both inside and outside of the closure. If you want to use the outside context of this inside the get-closure scope, you could do:

var that = this;
client.get("URL", function (data, response) {
        console.log(data['Keys'].length);
        count = data['Keys'].length;
        that.emit(':tell', 'There are ' + count + ' items in your s3 bucket.');
});