How to add key pairs to object literals using loop--WITHOUT overriding existing entries?

223 views Asked by At

I'm reading input field 'name' and 'value' attributes from ul lists. No two lists have the same amount of inputs and the 'name' and 'value' attributes are unknown till read.

<ul id="options_set1">
    <li><input name="width" value="10" /></li>
    <li><input name="height" value="20" /></li>
    <li><input name="depth" value="5" /></li>
</ul>
<ul id="options_set2">
    <li><input name="finish" value="printed" /></li>
    <li><input name="mounting" value="spacer" /></li>
</ul>

I iterate through all the inputs, gathering ul id 'options_set_X' as the literal for my objects, and name:value pairs:

var signState = {}; //My object to be populated

var optionSet = '';
var optionName = '';
var optionValue = '';

$("ul li input").each(function() {
  var optionSet = $(this).parent().parent().attr('id');
  signState[optionSet] = {};
  optionName = $(this).attr('name');
  optionValue = $(this).val();
  signState[optionSet][optionName] = optionValue;
});

What I cannot wrap my head around is how to prevent this loop from replacing any existing name:value pairs in each 'optionSet' literal in the object?

I suspect it is because I restart the signState[optionSet] = {}; literals.

I need a way to add name:value pairs for a given literal without disturbing any existing associations.

Nothing I read online deals with this specific case, because I use variables for both key names and key values - which complicates matters.

2

There are 2 answers

0
somethinghere On BEST ANSWER

Try this:

var signState = {};

$("ul li input").each(function() {
    var set, name, value;
    set    = $(this).parent().parent().attr('id');
    name   = $(this).attr('name');
    value  = $(this).val();

    /* Create a fresh object if it doesn't exist, 
     * otherwise assign it the existing one. */
    signState[set] = signState[set] || {};

    /* Again, assign a fresh value if it was undefined or empty 
     * otherwise assign it the existing one. */
    signState[set][name] = signState[set][name] || value;

});

Now if the value you are setting is false or 0, then it will be overwritten. If you don't want that, you have to use the tertiary operator to ensure you get it right:

signState[set][name] = typeof signState[set][name] !== "undefined"
    ? signState[set][name]
    : value;

The tertiary operator syntax is as follows: definition = when is true ? this : else this; - which can be very useful for this.

1
Matthew6 On

Following from somethinghere's comment and answer, I was able to get perfect results with this:

var signState = {}; //My object to be populated

var optionSet = '';
var optionName = '';
var optionValue = '';

$("ul li input").each(function() {
  optionSet = $(this).parent().parent().attr('id');
  signState[optionSet] = {};
  
  //The solution - because it prevents overriding existing literals, so name:value pairs are neatly written to each literal if they don't already exist
  if(!signState[optionSet]) { 
    signState[optionSet] = {};
  }
  //---------
  
  optionName = $(this).attr('name');
  optionValue = $(this).val();
  signState[optionSet][optionName] = optionValue;
});