Search code examples
javascriptjavascript-objects

JavaScript seemingly unable to access object property


So I have this object, Looks like this: enter image description here

I am trying to access the when_is_meeting property. I dont have any issue accessing any other property in this object. But if I try to access when_is_meeting I get an undefined as seen above next to "WHEN IS IT"

This is what the code looks like....

var listOfObjects = [];
    for (var modelData in responseData) {
        listOfObjects.push(service.create(name, responseData[modelData]));
        console.log('RESP', response.data.content[modelData]);
        console.log('WHEN IS IT!!!',response.data.content[modelData].when_is_meeting);
    }

Does anyone know what the heck is going on here? Did I spell something wrong? I've been over it 50 times. Must be something simple im overlooking.

----------------EDIT------HERE IS THE WHOLE SERVICE----------------------

    service.fetch = function (name, id, options) {
    options = options || {};
    const ModelClass = service.models[name];
    const baseUrl = ModelClass.getUrl(service.getBaseUrl(ModelClass), ModelClass.getModelName());
    let url;
    let paged = false;
    let pageList = false;


    if (id) {
        if (id instanceof models.BaseModel) {
            const BaseModelModelName = id.getModelName();
            let baseModelWithId = ModelClass.getUrl(service.getBaseUrl(), BaseModelModelName);
            url = [baseModelWithId, id.getId(), ModelClass.getModelName(), ''].join('/');
            pageList = true;
        } else {
            url = [baseUrl, id].join('/');
        }
    } else {
        pageList = true;
        url = [baseUrl, ''].join('/');
    }

    if (options.path) {
        url = url + options.path;
        delete options.path;
    }

    if (typeof options.paged === 'object') {
        let currentPage = options.paged.page;
        let pageSize = options.paged.page_size || 20;
        paged = options.paged;
        options.page = currentPage;
        options.size = pageSize;

        if (options.paged.sort) {
            let sortParam = options.paged.sort;

            options.sort = sortParam.param+','+sortParam.order;
        }

        delete options.paged;
    }

    return AuthRequestsService.load.then(function () {

        return $http({
            method: 'GET',
            url: url,
            headers: {
                'Authorization': AuthRequestsService.getAuthorizationHeader(),
            },
            params: options,
            json: true
        });
    }).then(function (response) {
            console.log('RESPONSE',response);
            for (let i = 0; i < response.data.content.length; i++){

              if (response.data.content[i].activity_history_type == 3){

                let builder = JSON.parse(response.data.content[i].relations);
                let secondaryUrl = AppSettings.apiUrl + ['/advisor/meetings', builder.meeting].join('/');

                $http({
                    url: secondaryUrl,
                    headers: {
                        'Authorization': AuthRequestsService.getAuthorizationHeader(),
                    },
                    method:'GET',
                    json:true,

                }).then(function(res){
                   response.data.content[i].when_is_meeting = res.data.meeting_date;
                   console.log('WHEN IS',response.data.content[i].when_is_meeting); // <-- this works
                })
              }
            }
            if (!pageList) {
                return service.create(name, response.data);
            } else {
                let responseData = response.data;
                if (paged) {
                    responseData = response.data.content;
                }

                var listOfObjects = [];
                for (var modelData in responseData) {
                    listOfObjects.push(service.create(name, responseData[modelData]));
                    console.log('RESP', response.data.content[modelData]);
                    listOfObjects[modelData].when_is_meeting = response.data.content[modelData].when_is_meeting;
                    listOfObjects[modelData].whatever = 44;
                    console.log('response.data.content[modelData].when_is_meeting',response.data.content[modelData].when_is_meeting);
                    console.log('listOfObjects[modelData].when_is_meeting', listOfObjects[modelData].when_is_meeting);
                    console.log('listOfObjects[modelData].whatever', listOfObjects[modelData].whatever);
                    console.log('Keys', Object.keys(response.data.content[modelData]));

                    // console.log('PRE IF', response.data.content[modelData].when_is_meeting);
                    // listOfObjects[modelData].when_is_meeting = response.data.content[modelData].when_is_meeting;
                    // console.log('IFFFFFFFFFFFFFFFFFFFFF', listOfObjects[modelData].when_is_meeting);
                    // console.log('IN FOR LOOP RESP', response.data.content[modelData].when_is_meeting);
                    // console.log('listOfObjects[modelData] PART 2', listOfObjects[modelData]);
                    function testForKey() {
                        if (typeof response.data.content[modelData].when_is_meeting !== "undefined") {
                            // when_is_meeting now exists! Do stuff with it here.
                            console.log("We now have the key:", response.data.content[modelData].when_is_meeting)
                        }
                        else {
                            // when_is_meeting is still missing. Try again in 200ms.
                            window.setTimeout(testForKey, 200);
                            console.log('TTTIIMMMEEEEOOOUUUTTT');
                        }
                    }
                    testForKey();
                }


                if (paged) {
                  console.log('#########################', listOfObjects);
                    return {
                        objects: listOfObjects,
                        totalPages: response.data.totalPages,
                        currentPage: response.data.number,
                        isMore: (!response.data.last),
                        totalElements: response.data.totalElements
                    };
                } else {
                    return listOfObjects;
                }
            }
    });
};

enter image description here


Solution

  • This problem occurs because when you expand the toggle to view an object the console show what it has now, not what it had at the time it was logged.

    This is explained well here: http://felix-kling.de/blog/2011/08/18/inspecting-variables-in-javascript-consoles/

    This scenario is not uncommon when you are working with Ajax. You are trying to access the result before everything has completed; ie, something else in your code is working on your response.data and adding in the missing key after your console.log statements.

    This is confirmed by the logging statement suggested in the comments above by @Steven. Object.keys(response.data.content[modelData])) will show the keys available at the time the log statement is made and hence does not have the same problem as just logging the object itself to the console. The results from that confirm when_is_meeting is indeed missing at log-time.

    To fix this properly, we need to see more of your code so we can work out why you are trying to access your result before other things finish using it.

    Or you can do a crude workaround using timeouts to test the response.data.content[modelData] for the availability of when_is_meeting and only access it when it exists, like the example below. But this is not really recommended - much better to figure out where the problem lies in your response handling.

    var listOfObjects = [];
    for (var modelData in responseData) {
        listOfObjects.push(service.create(name, responseData[modelData]));
    
        // testForKey looks for the required key 'when_is_meeting' and if it does not
        // exist it starts a timeout to test for it again in the future.
        function testForKey() {
            if (typeof response.data.content[modelData].when_is_meeting !== "undefined") {
                // when_is_meeting now exists! Do stuff with it here.
                console.log("We now have the key:", response.data.content[modelData].when_is_meeting)
            }
            else {
                // when_is_meeting is still missing. Try again in 200ms.
                window.setTimeout(testForKey, 200);
            }
        }
        testForKey();
    }
    

    (I've not tested this code - it might have syntax errors)

    Update - a fix for your supplied code

    Your supplied code shows that as predicted the when_is_meeting key is being added to your result in a separate Ajax call. This call complete asynchronously and as such its result is not available to your log statements below it. This fragment shows one approach for fixing it. As before, I have not syntax-checked this code.

    return AuthRequestsService.load.then(function () {
        return $http({
            method: 'GET',
            url: url,
            headers: {
                'Authorization': AuthRequestsService.getAuthorizationHeader(),
            },
            params: options,
            json: true
        });
    }).then(function (response) {
        console.log('RESPONSE',response);
        for (let i = 0; i < response.data.content.length; i++){
    
          if (response.data.content[i].activity_history_type == 3){
    
            let builder = JSON.parse(response.data.content[i].relations);
            let secondaryUrl = AppSettings.apiUrl + ['/advisor/meetings', builder.meeting].join('/');
    
            // Store the result of this $http call as a promise.
            response.data.content[i].when_is_meeting_promise = $http({
                url: secondaryUrl,
                headers: {
                    'Authorization': AuthRequestsService.getAuthorizationHeader(),
                },
                method:'GET',
                json:true,
    
            })
            // Remove your .then handler from here. It will be dealt with below.
            //.then(function(res){
            //   response.data.content[i].when_is_meeting = res.data.meeting_date;
            //   console.log('WHEN IS',response.data.content[i].when_is_meeting); // <-- this works
            //})
          }
        }
        if (!pageList) {
            return service.create(name, response.data);
        } else {
            let responseData = response.data;
            if (paged) {
                responseData = response.data.content;
            }
    
            var listOfObjects = [];
            for (var modelData in responseData) {
                // OK, now access the promise you stored above. This means you'll be sure you'll
                // have the when_is_meeting key.
                responseData[modelData].when_is_meeting_promise.then(function(when_is_meeting_result) {
                    // Now you can copy the neeting date into your responseData object.
                    responseData[modelData].when_is_meeting = when_is_meeting_result.data.meeting_date;
    
                    // Carry on....
                    listOfObjects.push(service.create(name, responseData[modelData]));
                    console.log('RESP', response.data.content[modelData]);
    
                    // This should now work...
                    console.log('response.data.content[modelData].when_is_meeting',response.data.content[modelData].when_is_meeting);
                });
            }
        }
    });