1

I looked at similar questions and tried Object.key(patientList).length but it returns 0. I was recommended to use callbacks and this how I am implementing it.

var data;
var patientList = {};
var parseDate = d3.time.format("%d/%m/%y").parse;

function input_Data()  {

    d3.json("data.php", function(error, json)  {
    if (error) return console.warn(error);
        data = json;
        console.log(data);

           for(var i = 0; i < data.length; i++)  {
            var name = data[i].name;
                //data[i].dates = parseDate(data[i].dates);
            if(!patientList[name])  {

            var newPatient = {
                dates: [data[i].dates],
                alpha: data[i].alpha,
                beta: data[i].beta
            };

            patientList[name] = newPatient;

            } else  {

            patientList[name].dates.push(data[i].dates);
            }
        }
        console.log(patientList);
            console.log(Object.keys(patientList).length);
            console.log(Object.keys(patientList));
       });

}

function number_of_patients(callback) {
    callback();
    console.log(patientList);
    console.log(Object.keys(patientList).length);
    console.log(Object.keys(patientList));
}

number_of_patients(input_Data);

console.log inside the input_Data function displays correct results with length 4. And console.log in the number_of_patients displays correct patientList but 0 length and doesn't display name (keys) either. I have read similar posts but still can't fix the problem here.

Any help would be much appreciated.

user2398101
  • 339
  • 3
  • 9
  • 21
  • Where are you attempting to use `length` in relation to the `patientList` object? I don't see it anywhere in your code – Phil Mar 19 '14 at 03:09
  • 1
    `Object.key(patientList).length` will work if you call it after the object was populated. – Felix Kling Mar 19 '14 at 03:11
  • 2
    I'm going to assume you need to read this - [How to return the response from an AJAX call?](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) – Phil Mar 19 '14 at 03:12
  • 3
    Btw, it's `Object.keys` – sabof Mar 19 '14 at 03:12
  • @Phil- I wanna draw a scatterplot using names on y-axis and dates on x-axis, so need number of patient names to define domain for y-axis. – user2398101 Mar 19 '14 at 03:15
  • @user2398101 I didn't ask you what you were trying to do; I asked you **where** you were attempting to use the `length` property in relation to the `patientList` object. – Phil Mar 19 '14 at 03:17
  • 2
    Well, yeah, in your edit you are calling `Object.keys` **before** the object is populated. All the code that has to work with the data has to be invoked from the callback you pass to `d3.json`. Read the question/answer Phil linked to, it hopefully explains the problem. – Felix Kling Mar 19 '14 at 03:18
  • @sabof Object.keys() is not standard JavaScript. But some libraries provide it, such as underscore: http://underscorejs.org/#keys – Paul Mar 19 '14 at 03:18
  • 2
    @Paul: http://es5.github.io/#x15.2.3.14 – Felix Kling Mar 19 '14 at 03:18
  • 1
    @Paul - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys#Browser_compatibility. There's also a polyfill for IE < 9 on that same page – Phil Mar 19 '14 at 03:19
  • Think about it like this: If the code was executed synchronously, then there would be no reason to pass a callback. You could just write `var data = d3.json(...);` and do your data processing after that line. But that's **not** the case, so it should be pretty straightforward that you have to put the code that should work with the data inside the callback. If I'm not wrong, there are primarily two reasons why a function accepts a callback: a) The operation is asynchronous. b) It applies the function on each element of a collection. `d3` is not a collection, so it must be `a)` :) – Felix Kling Mar 19 '14 at 03:31
  • @FelixKling - I tried putting d3.json in a function that returns patientList and call the function: var result = inputData() and use Object.keys(result).length. But this doesn't work either. – user2398101 Mar 19 '14 at 03:44
  • @FelixKling - On putting console.log after d3.json finishes, the patientList seems to be correctly populated. – user2398101 Mar 19 '14 at 03:50
  • Fixed the problem, Thanks for help guys :) – user2398101 Mar 19 '14 at 06:56

1 Answers1

1

In Javascript, generic objects do not have a length property.

Common facts about Javascript objects:

  • Objects contain key: value pairs where the keys are strings and values may be any type.
  • Objects do not have a .keys() method to get all of the keys, except...
  • Ecmascript 5 provides an Object.keys() which can be called explicitly as do some 3rd party libs like underscore.js
  • initialized using curly braces {} and key:value pairs

Before that, the usual way to count or access all of the keys unique to a specific instance of an object is with a loop like the following:

l=0;    
for(var k in obj){ 
        if (obj.hasOwnProperty(k)){
          // hasOwnProperty ignores keys from the prototype chain
          // do something with key k, value obj[k]
           ++l;
        }
    }
// the object has l keys specific to this instance

If you need to quickly get a length you should consider using an array object:

  • Array objects (x = [1,2,3,'sam',{'name':'fred', 'status': 'dead'}]) have numeric indices starting with 0 and can contain arbitrary type members.
  • have a length property (x.length is 5)
  • values are accessed by numeric indices with square brackets, i.e. x[2] is 3
  • initialized use square brackets [] containing a comma separated list of values

And as others said in comments, asynchronous calls generally return immediately -- and without the data or object you want in scope. To access the data you must execute code in the context where the data is defined, i.e. write code that accesses the asynchronous data/object in a callback function, not the main code.

Paul
  • 26,170
  • 12
  • 85
  • 119
  • 1
    You are right, but there is a method called `Object.keys` which returns an array of property names. http://es5.github.io/#x15.2.3.14, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys – Felix Kling Mar 19 '14 at 03:17
  • @FelixKling Thanks. Good to know. Will edit. – Paul Mar 19 '14 at 03:21