2

I have a function which returns a list of objects in Javascript, and I'm calling this function from another and attempting to use some of the values from it, but whenever I try to access said values, they come back undefined.

This is my function which generates the list - the idea is that it creates a sqlite3 database if it does not exist, and returns an array containing every event.

function listAllEvents() {
    const sqlite3 = require('sqlite3').verbose();
    const db = new sqlite3.Database('schedule.db');

    const selectionArray = [];

    db.serialize(() => {
        db.run(`
        CREATE TABLE IF NOT EXISTS todo (
            name text,
            date text,
            id text primary key
            )
        `);

        db.all('SELECT * FROM todo ORDER BY date', [], (err, rows) => {
            if (err) {
                throw err;
            }

            rows.forEach((row) => {
                selectionArray.push(row);
            });
        });
    });
    return selectionArray;
}

I call this function from another, but when I try to access values from the array, they don't seem to be working and I can't quite figure it out.

function displayUpcomingEvents() {
    const events = listAllEvents();

    // console.log(events); <-- This line here! In the console, it correctly states the length of the array
    // console.log(events.length) <-- This line, however, returns 0. Why?
    // console.log(events[0]) <-- This doesn't work either, it just returns "undefined".

    for (let i = 0; i < events.length; i += 1) {
        $('#upcomingEvents').after('<li>asdf</li>');
    }
}

For example, if I were to create two events in the database, through the console,

events is an Array(2) with indices
- 0: {name: "my_event", date: "2019-06-04", id: "c017c392d446d4b2"}
- 1: {name: "my_event_2", date: "2019-06-04", id: "6d655ac8dd02e3fd"},

events.length returns 0,
and events[0] returns undefined.

Why is this, and what can I do to fix it?

  • Not related to your question, but I'd suggest you to change that `events` name for your array. You almost hit `event`: https://developer.mozilla.org/en-US/docs/Web/API/Window/event – Gerardo Furtado Jun 13 '19 at 03:09
  • Possible duplicate of [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – zero298 Jun 13 '19 at 03:47

2 Answers2

0

The possible reason why this is happening, is because of the async nature of JS, that means all the console.log statements are getting executed before the successful execution of the listAllEvents() function,

So my suggestion is to try using the promises, and perform all the actions mentioned after the listAllEvents() function only when that function returns a promise.

You can also try making the function async and using await to wait for its successful execution. (Much Smarter Choice will be using async)

Link to ASYNC Functions and Usage Link to Promises

Also you can check the validity of answer by doing console.log(row) where you are pushing rows to the array. You will observer that the console.log(row) will be executed at the last, after printing events and other log statements.

0

The problem is that your function is returning the variable before a value is set. The db.serialize function will run asynchronously (outside the normal flow of the program) and the return statement will run immediately after. One thing you can do is use async/await in conjunction with Promise. In this case the the variable results will wait for the promise to be resolved before continuing to the next line.

async function listAllEvents() {    
    const selectionArray = [];

    let promise = new Promise( function (resolve, reject) {
        db.serialize(() => {
            db.run(
            CREATE TABLE IF NOT EXISTS todo (
            name text,
                date text,
                id text primary key
                )
            );

            db.all('SELECT * FROM todo ORDER BY date', [], (err, rows) => {
                if (err) {
                    // add code here to reject promise
                    throw err;
                }

                rows.forEach((row) => {
                    selectionArray.push(row);
                });
                resolve(selectionArray);// resolve the promise
            });
        });
    });

    let results = await promise;
    return results; 
};

async function displayUpcomingEvents() {
    const events = await listAllEvents();

    // console.log(events); <-- This line here! In the console, it correctly states the length of the array
    // console.log(events.length) <-- This line, however, returns 0. Why?
    // console.log(events[0]) <-- This doesn't work either, it just returns "undefined".

    for (let i = 0; i < events.length; i += 1) {
        $('#upcomingEvents').after('<li>asdf</li>');
    }
}

Note here that the displayUpcomingEvents function will also need to be async or you cannot use the await keyword.

Additional reading for Promise keyword MDN: Promise

Additional reading for Async/Await MDN: Asyn/Await

Cody Pace
  • 180
  • 14