sean.boyer
sean.boyer

Reputation: 1237

Clean Method to Normalize Javascript Object Properties

I have an array of javascript objects that represent users, like so:

[
  { userName: "Michael",
    city: "Boston"
  },
  { userName: "Thomas",
    state: "California",
    phone: "555-5555"
  },
  { userName: "Kathrine",
    phone: "444-4444"
  }
]

Some of the objects contain some properties but not others. What I need is a clean way to ensure ALL objects get the same properties. If they don't exist, I want them to have an empty string value, like so:

 [
    { userName: "Michael",
      city: "Boston",
      state: "",
      phone: ""
    },
    { userName: "Thomas",
      city: "",
      state: "California",
      phone: "555-5555"
    },
    { userName: "Kathrine",
      city: "",
      state: "",
      phone: "444-4444"
    }
]

Update I should have been a little more specific. I was looking for an option that would handle this situation dynamically, so I don't have to know the properties ahead of time.

For jQuery specific, the $.extend() option is a good one, but will only work if you know ALL the properties ahead of time.

A few have mentioned that this should probably be a server-side task, and while I normally agree with that, there are two reasons I'm not handling this at the server-side: 1) it will be a smaller JSON object if say 900 of 1000 objects only contain 1 of a possible 9 properties. 2) the "empty" properties need to be added to satisfy a JS utility that could be replaced in the future with something that doesn't care if some properties are missing.

Upvotes: 5

Views: 7148

Answers (6)

doku
doku

Reputation: 36

Fiddle This function stores unique object keys in an array and so you can run your array of objects through it and then use one of the other supplied answers to add the keys to the objects if they do not exist:

function uniqueKeys(){
    var keys=[];
    function getUniqueKeys(){
        return keys
    }
    function addObject(obj){
        for (var k in obj){
            keys = _.union(keys,[k]);
        }
    }
    return {
        addObj: addObject,
        getKeys: getUniqueKeys
    }
}

Usage:

var objArr =  [{ userName: "Michael", city: "Boston"  },
{ userName: "Thomas", state: "California", phone: "555-5555"},
{ userName: "Kathrine",phone: "444-4444" }];

var uniq = new uniqueKeys();
_.each(objArr, function(v){
    uniq.addObj(v)
});
var keys = uniq.getKeys();
alert(keys);

Upvotes: 0

user2033671
user2033671

Reputation:

Since you are using jQuery you can abuse $.extend

function Person(options){
    return $.extend({
         userName:"",
         city: "",
         state:"",
         phone: ""
    },options);
}

$.map([{}],Person)

update

Heres a way to have dynamic default properties

function mapDefaults(arr){
    var defaultProperties = {}
    for(var i =0; i < arr.length; i++){ 
        $.each(arr[i],function(key){
            defaultProperties[key] = "";
        });
    }
    function Defaulter(obj){
        return $.extend({},defaultProperties,obj);
    }
    return $.map(arr, Defaulter);
}

mapDefaults([{a:"valA"},{b:"valB"}]);
/* produces:
 [{a:"valA",b:""},{a:"",b:"valB"}]
*/

Upvotes: 6

daekano
daekano

Reputation: 84

The way that is easiest to understand is probably to make a function that accepts an object and uses if statements as existence checks, assigning a default value if it doesn't find it.

function normalize(object) {
  if(typeof object.userName === 'undefined') {
    object.userName = 'Default Value';
  }
  if(typeof object.city === 'undefined') {
    object.city = 'Default Value';
  }
  if(typeof object.state === 'undefined') {
    object.state = 'Default Value';
  }
  if(typeof object.phone === 'undefined') {
    object.phone = 'Default Value';
  }

  return object;

}

var userArray = [{},{},{}].map(normalize);

We can also go the constructor route and provide default values on object creation.

function User (data) {
  this.userName = data.userName || 'Default Value';
  this.city = data.city || 'Default Value';
  this.state = data.state || 'Default Value';
  this.phone = data.phone || 'Default Value';

 return this;
}

var userArray = [{},{},{}].map(function(o){
 return new User(o);
});

Of course this depends on one specific type of data and won't extend to other properties and isn't very DRY, but as I said, this is probably the easiest to understand from a beginner's standpoint.

Upvotes: 2

PlantTheIdea
PlantTheIdea

Reputation: 16369

Something you might try is creating a coalescing function:

function coalesceValues(val){
    switch(val)
        case undefined:
        case null:
            return '';
            break;
        default:
            return val;
            break;
    }
}

Or if you wanted to forego customization for simplicity:

function coalesceValues(val){
    return val || '';
}

And then apply it when assigning variables:

var city = coalesceValues(obj.city);

This way you don't need to do any crazy breakdown to array and loop or anything, you can apply it to whatever you want, and you can also customize the values you want to coalesce.

Just offering an alternative idea.

Upvotes: 2

Jason P
Jason P

Reputation: 27022

This should probably be a server-side task, but..

If you know all the possible properties ahead of time, you could do this:

http://jsfiddle.net/BMau9/

var properties = ['userName', 'city', 'state', 'phone'];

var data = [{
    userName: "Michael",
    city: "Boston"
}, {
    userName: "Thomas",
    state: "California",
    phone: "555-5555"
}, {
    userName: "Kathrine",
    phone: "444-4444"
}];

for (var i in data) {
    for (var j in properties) {
        data[i][properties[j]] = data[i][properties[j]] || '';
    }
}

Upvotes: 1

spassvogel
spassvogel

Reputation: 3541

var list = [
  { userName: "Michael",
    city: "Boston"
  },
  { userName: "Thomas",
    state: "California",
    phone: "555-5555"
  },
  { userName: "Kathrine",
    phone: "444-4444"
  }
];


for(var i = 0; i < list.length; i++){
    if(list[i].state === undefined)
        list[i].state = "";
    if(list[i].phone === undefined)
        list[i].phone = "";
};
 console.log(list); 

http://jsfiddle.net/g5XPk/1/

Upvotes: 1

Related Questions