0

I've never worked on this sort of thing before and I kind of jumped in the deep end, but I feel like I'm really close. I'm trying to add a dynamically populated select list to the edit dialog of a node red node. I wrote a method in the client that calls a method I wrote in the server. The call executes. The server retrieves the data (confirmed via debug print to the console), but the client receives something other than the data. I've not dont much javascript before, but according to my understanding of promises, it seems like the data should be sent to the client, so I don't understand what I'm missing.

The server method in server.js:

getCircles() {
    var node = this;
    return node.updateSession(function (session) {
        return life360.circles(session)
            .then(circles => {
                console.log("this gets called after the end of the main stack. the value received and returned is: " + JSON.stringify(circles));
                return circles;
            })
    });
}

The server "requires" ../index.js, which has:

/**
 * Fetch the user's circles
 */
module.exports.circles = function (session) {
  if (!session) throw new Error("session not specified");
  return new Promise((resolve, reject) => {
    const LIFE360_CIRCLES_URL = "https://api.life360.com/v3/circles"
    const options = {
      url: LIFE360_CIRCLES_URL,
      headers: {
        'Authorization': `${session.token_type} ${session.access_token}`
      },
      json: true
    };
    // console.log(`Fetching circles at ${LIFE360_CIRCLES_URL}`);
    request(options)
      .then(response => {
        let circles = response.body.circles;
        console.log("Returning circles: " + JSON.stringify(circles));
        resolve(circles);
      });
  });
}

The client method that calls the server method (getCircles) in location.js:

let circles = node.server.getCircles();
console.log("circles = " + JSON.stringify(circles));

Here's what I get in the log (I redacted the ids, though I don't know if I needed to):

circles = {"isFulfilled":false,"isRejected":false}
Returning circles: [{"id":"xxxxxxxx","name":"Rob's Homes","color":"da22d5","type":"basic","createdAt":"1379025809","memberCount":"4","unreadMessages":"0","unreadNotifications":"0","features":{"ownerId":null,"skuId":null,"premium":"0","locationUpdatesLeft":0,"priceMonth":"0","priceYear":"0","skuTier":null}},{"id":"xxxxxxxx","name":"Rob's Family","color":"f05929","type":"basic","createdAt":"1393782349","memberCount":"4","unreadMessages":"0","unreadNotifications":"0","features":{"ownerId":null,"skuId":null,"premium":"0","locationUpdatesLeft":0,"priceMonth":"0","priceYear":"0","skuTier":null}},{"id":"xxxxxxxx","name":"Leach Family","color":"7f26c2","type":"basic","createdAt":"1393785316","memberCount":"6","unreadMessages":"0","unreadNotifications":"0","features":{"ownerId":null,"skuId":null,"premium":"0","locationUpdatesLeft":0,"priceMonth":"0","priceYear":"0","skuTier":null}}]
this gets called after the end of the main stack. the value received and returned is: [{"id":"xxxxxxxx","name":"Rob's Homes","color":"da22d5","type":"basic","createdAt":"1379025809","memberCount":"4","unreadMessages":"0","unreadNotifications":"0","features":{"ownerId":null,"skuId":null,"premium":"0","locationUpdatesLeft":0,"priceMonth":"0","priceYear":"0","skuTier":null}},{"id":"xxxxxxxx","name":"Rob's Family","color":"f05929","type":"basic","createdAt":"1393782349","memberCount":"4","unreadMessages":"0","unreadNotifications":"0","features":{"ownerId":null,"skuId":null,"premium":"0","locationUpdatesLeft":0,"priceMonth":"0","priceYear":"0","skuTier":null}},{"id":"xxxxxxxx","name":"Leach Family","color":"7f26c2","type":"basic","createdAt":"1393785316","memberCount":"6","unreadMessages":"0","unreadNotifications":"0","features":{"ownerId":null,"skuId":null,"premium":"0","locationUpdatesLeft":0,"priceMonth":"0","priceYear":"0","skuTier":null}}]

Why don't I get the value reported in the console from the server method, in the client?

I have tried putting 'resolve' in various places, but I can't seem to figure out where to put it to turn the promise into the content on the client side.

In an experiment, I tried providing a callback method to getCircles that does node.send([{payload: circles}]) and that ended up sending the circle data out of the node red node I'm working on. Then I tried just making it return circles, and I still get the unresolved promise object.

There's another method called getCircle in ../index.js and location.js uses that to extract member data, which works... Maybe I need to edit getCircles to build and return the data (a hash of circle IDs -> circle names) that I planned to build after receiving the circle data?

hepcat72
  • 890
  • 4
  • 22
  • Without knowing the exact relationship between the server script and client script here, it's obvious from the console that the clientside `getCircles()` method returns a promise. You simply need to handle it as any other promise and get the value from its fulfilment . – Lennholm Oct 19 '20 at 02:14
  • By your code, `circles` would be a promise which is not been resolved. – sujeet Oct 19 '20 at 02:17
  • Cool. Yeah, I obviously don't know what I'm doing. I did try sticking resolve in a couple spots, but I'd gotten errors about the resolve method not existing. Now that I know that's the right direction, I'll look closer. I had inferred fulfillment being false to mean that it wasn't returned. – hepcat72 Oct 19 '20 at 02:29
  • Looks like resolve isn't defined in the server because the Promise is in a difference file that is "required" at the top of the server code? Maybe I need to make a separate method that returns a resolved response there and sends that back. – hepcat72 Oct 19 '20 at 12:55
  • No no, the resolve function is only relevant when creating a promise, not when handling one. Handling a promise is what you do in the server `getCircles()` function, `life360.circles(session)` returns a promise and you're handling it with its `then()` method. Just do the same in your client script, i.e `node.server.getCircles().then(circles => console.log(circles))` instead of `let circles = node.server.getCircles();`. – Lennholm Oct 19 '20 at 21:25
  • Also, `request()` already returns a promise so there's no need to wrap it in a new promise, that's actually an anti-pattern (check this out: https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it). Just use the promise already provided by `request()` instead, i.e `return request(options)` and inside its `then()` callback, `return circles` instead of `resolve(circles)`. – Lennholm Oct 19 '20 at 21:30
  • I don't understand the console.log call. I want to process the circles data. How do I set circles so that I can use it in the code so I can build a select list and supply it to the edit dialog? – hepcat72 Oct 19 '20 at 21:31
  • I was only printing to the log to see what I have. The problem is what I have is the promise json and not the circles data. – hepcat72 Oct 19 '20 at 21:32
  • You need to do everything that depends on the `circles` data inside that `then()` callback, i.e where I put the `console.log()` call. This is how dealing with asynchronous processes in Javascript works since JS is single-threaded. If you want a neater syntax that is more similar to regular synchronous coding you can look up *async-await*. – Lennholm Oct 19 '20 at 21:37
  • Ok, fair enough, but even if I put code there to process it, I still can't get the results to the edit dialog. The location.js code that is making the call to the server will send the result (select list html) back to the edit dialog. But all I seem to be able to get in location.js is that promise json stuff. – hepcat72 Oct 19 '20 at 21:41
  • I can send test values from the location.js code to populate the select list and I can trigger the call to the server to retrieve the data I really want to use to populate that select list, but I can't get that data back to supply back to the edit dialog. – hepcat72 Oct 19 '20 at 21:43
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/223324/discussion-between-hepcat72-and-lennholm). – hepcat72 Oct 20 '20 at 01:05

0 Answers0