tags:

views:

125

answers:

4

I have the following JSON response from a ajax-request.

var json = {
"response": {
 "freeOfChargeProduct":{  
  "description":"Product",  
  "orderQty":5,
  "productName":"XYZ",
  "qty":6,
  "details": {
   "price" : 55.5, 
   "instock": "true",
   "focQuantity":1
  }
 }, 
 "orderLineId":4788,
 "totalOrderLinePrice":"741.36",
 "totalOrderPrice":"1,314.92",
 "totalQty":17
 }
};

The JSON dosen't always return a "freeOfChargeProduct" property. So if I want to get the "freeOfChargeProduct" price, then I have to do the following:

var getFreeOfChargeProductPrice = function() { 
   var r = json.response;
   if (r && r.freeOfChargeProduct && r.freeOfChargeProduct.details) {
      return r.freeOfChargeProduct.details.price;         
   }
   return null;
};

No problems. But it's very annoying to check every property in the object, so I created a function that check if a property in a object is defined.

var getValue = function (str, context) {
    var scope = context || window,
        properties = str.split('.'), i;
    for(i = 0; i < properties.length; i++) {
      if (!scope[properties[i]]) {                       
         return null;
      } 
      scope = scope[properties[i]];        
    }
    return scope;
};

var price = getValue('json.response.freeOfChargeProduct.details.price');
//price is null if no such object exists.

Now to my question: Is this a good or bad way to check if a property exists in an object? Any better suggestions/methods?

EDIT:

I don't wan't to use the &&-operator. I am lazy and I'm looking for a reusable method to check if a object (or property of a object) is defined.

:)

Thanks!

+4  A: 
Šime Vidas
You call it guard? I call it logical AND.... never heard of *guard operator* before but maybe someone can point me to a source?
Felix Kling
Nisse
Guard is his nickname. (Because it guards the second operand: if the first operand is falsy, it returns the first operand. If the first operand is truthy, it returns the second operand.)
Šime Vidas
@Felix The source is Douglas Crockford from Yahoo. I got this nickname from him. http://javascript.crockford.com/survey.html
Šime Vidas
Mmh, I would be careful with these kind of nicknames. Your explanation might "work" in JavaScript, but not in e.g. PHP. I would say it can *act like a guard*... Anyway, this might be splitting hairs, so nevermind! Thanks for the link!
Felix Kling
Šime Vidas
KakambaWeb
Šime Vidas
A: 

You could do something like this:

try{
    var focp = json.response.freeOfChargeProduct
    var text = "You get " + focp.qty + " of " +
        focp.productName +
        " for only $" + (focp.qty-focp.details.focQuantity)*focp.details.price +
        ", You save $" + focp.details.focQuantity*focp.details.price;
    $("order_info").innerText = text;
} catch(e) {
    // woops, handle error...
}

It would generate a message like this from the provided data in your question if the fields exists:

You get 6 of XYZ for only $277,5, You save $55.5

If the data is non-existing, you'll end up in the catch block. You could always just to a Try, Catch, Forget here if you can't come up with a way to handle the error (Maybe do a new AJAX request for the data?).

Frank
A: 
if(x && typeof x.y != 'undefined') {
    ...
}

// or better
function isDefined(x) {
    var undefined;
    return x !== undefined;
}

if(x && isDefined(x.y)) {
    ...
}

This will work for any data type in JavaScript, even a number that is zero. If you are checking for an object or string, just use x && x.y within the if statement, or if you already know that x is an object, if(x.y) ...

idealmachine
+1  A: 

Hello.

This is not a syntax issue as it is a design pattern issue.

Question A. * Do you have control of the json server?

If the answer to this is no, which I assume, the situation will be all on the client.

Please read this: http://martinfowler.com/eaaDev/PresentationModel.html

As the server is the source, in this case it will provide the model. This pattern specifies an additional artifact: The presentation model (PM). In javascript i would suggest two artifacts, a additional for the convertor code.

According to this design pattern the PM is responsible for converting the model to the PM, and back again if necessary. In your case no conversion from PM to M will ever occur.

This means that a js object has a method or constructor that digest the model and translate itself, with the help of the convertor (below).

Doing this you will end up with a PM looking like this:

var OrderlinePM = {
  "hasFreeOfCharge": false | true,
  "freeOfCharge" : {...}

enter code herethis.getFreeOfCharge = function() { ... } this.fromModel = function(jsonEntry, convertor) { //convert this with the convertor ;) to a for this specific view usable OrderlinePM // also inwith ... } "orderLineId":0, "totalOrderLinePrice":"741.36", "totalOrderPrice":"1,314.92", "totalQty":17 };

function mySpecialFunctionPMConvertor { this.fromModel = functiono() { ... //do strange stuff with the model and poulate a PM with it. } }

Ok, I give up trying to format code in this rich text editor :(

  • You can have several PM:s for diffrent tasks all depending on the same model object.
  • In addition this will make the converter object testable in something that could be automatically executed.... err ok maby manually, but anyway.

So the problem of the cumbersome reflection code is really not a problem. But cohersivness is a issue, expessially in JavaScript.

nisses kompis