0

I have a jQuery plugin that loads json data via an ajax call - the returned data is inserted into an existing object.

When I try and reference the newly inserted nodes I get an 'undefined' - though the data looks good in the console.

If I manually define the data then I can access it it fine - even though the structure is the same.

The data is loaded on the init event (there will be multiple function calls in the .then() but I'm just showing the initial call that is failing - each of these will reference the same _t.criteria.base.x where x is the inserted json ):

 var _t = this;

_t.init = function() {
        _s = $.extend({}, defaults, options);
        $.when( 
            loadDefaultCriteria() 
        ).then(
            renderCommunities
        );
    }

This loads the data:

_t.criteria = {
        base: {},
        current: {},
        picks:{}
    }; 

var loadDefaultCriteria = function() {
        $.getJSON
        (
            '/path/to/script.php',
            {
                action: 'loadDefaultCriteria',
            })
            .done( function( data ){
                _t.criteria.base = data;
            })
            .fail( function( jqxhr, textStatus, error ) {
                var err = textStatus + ", " + error;
                console.log( "Request Failed: " + err );
            });
        }

this is the code that fails (debug logs still in place)

var renderCommunities = function(){
        console.log(_t.criteria);
        var c = $(_s.containers.communities);
        var i = _t.criteria.base.communities;

        console.log(i);

        c.empty();

        c.append('<ul>');

        $.each( i, function( idx, _i ) {
                console.log(_i);
            });

    }

the console.log(_t.criteria) outputs this (I'm only showing the expanded tree for the base object ):

Object {base: Object, current: Object, picks: Object}
    base: Object
        communities: Object
             subscribed: Array[2]
                0: Object
                1: Object
             unsubscribed: Array[1]
                0: Object
   current: Object
   picks: Object

It doesn't matter which Object I try and reference below base they all return 'undefined', so in the code above console.log(_t.base.communities) will return undefined.

How do I insert a subset of JSON data/nodes into an existing object and then access them?

Zebedee
  • 5
  • 2
  • Please fix syntax error and indentation – A. Wolff Oct 30 '14 at 12:59
  • You haven't shown the relationship between the calls to `loadDefaultCriteria` and `renderCommunities`. Probably this is a duplicate of [How to return the response from an Ajax call?](http://stackoverflow.com/q/14220321/710446), but I don't think you've supplied enough information to be sure. – apsillers Oct 30 '14 at 13:04
  • Also, the observed inconsistency of `console.log` is likely the one addressed in [console.log() shows the changed value of a variable before the value actually changes](http://stackoverflow.com/q/11284663/710446) – apsillers Oct 30 '14 at 13:14
  • @apsillers I have edited the initial post to show how the 2 functions are called (on the init event of the plugin). – Zebedee Oct 30 '14 at 13:24
  • @Zebedee Oh, that's very simple, I think: your `loadDefaultCriteria` must `return $.getJSON(...)`. Otherwise, the `$.when` has no idea when to fire the `then` function. I haven't done a lot with deferreds, so I'm not 100% sure that will work, but I think it will. – apsillers Oct 30 '14 at 13:27

1 Answers1

0

$.when expects a Deferred object as its argument. Right now, loadDefaultCriteria doesn't return anything, so $.when is getting undefined as its argument. Instead, loadDefaultCriteria must return the Deferred object created by the $.getJSON(...) call:

var loadDefaultCriteria = function() {
    return $.getJSON( ... );
}

Your renderCommunities call happened before your getJSON call was complete. The reason your console.log call showed the updated object is because you inspected the logged object after the $.getJSON call compelted, and console.log always shows the object as it exists at inspection time. The order of events was:

  1. Initiate a getJSON call in loadDefaultCriteria
  2. Immediately run renderCommunities before the object updates
  3. Show the unexpanded object in the console output
  4. $.getJSON resolves and updates the object
  5. Seconds later, expand the object in the console output to see the object as it exists right now
Community
  • 1
  • 1
apsillers
  • 112,806
  • 17
  • 235
  • 239
  • Thank you! That's resolved it. I had tried using `var defer = $.Deferred()` and returning that var at the completion of `loadDefaultCriteria` but was still getting the same problem. Thanks again. – Zebedee Oct 30 '14 at 13:45