2

Consider the object:

{
  "status": {
    "affects": {
      "date_of_death": "date_of_death",
      "cause_of_death": {
        "affects": {
          "other_cause_of_death": "other_cause_of_death"
        },
        "value": "Other"
      }
    },
    "value": "Deceased"
  }
}

What I want to do is loop over this and add {hide: true}. But there are some rules:

  • If the key does not have object as a value, take the value and make it into {hide: true}
  • If it has affects, like cause of death does, add hide: true after value.

So the resulting object should be:

{
  "status": {
    "affects": {
      "date_of_death": {hide: true},
      "cause_of_death": {
        "affects": {
          "other_cause_of_death": {hide: true}
        },
        "value": "Other",
        "hide": true,
      }
    },
    "value": "Deceased"
  }
}

now this might seem easy, until you get something like this:

{
  "comorbidities": [
    {
      "affects": {
        "malignancy_type": {
          "affects": {
            "malignancy_type_other": "malignancy_type_other"
          },
          "value": "Other"
        }
      },
      "value": "malignancy"
    },
    {
      "affects": {
        "heritable_syndrome_type": "heritable_syndrome_type"
      },
      "value": "heritable syndrome"
    }
  ]
}

The exact same thing should happen here. Accept notice how its an array, This should do it recursively, deep diving into the affects, until no more can be found.

I have gotten this far:

export const createHiddenFields = (dependencies) => {
  let hiddenFields = {};

  if (dependencies === null) {
    return hiddenFields;
  }

  for (const key in dependencies) {
    if (dependencies[key].hasOwnProperty('affects')) {
      hiddenFields[key] =
    } else {

    }
  }

  return hiddenFields;
}

But I am lost as to how to finish this. I know I want it recursive, but I also want it fast, but still legible.

Any Ideas?

TheWebs
  • 12,470
  • 30
  • 107
  • 211
  • 1
    `status` has an `affects` key. Why doesn't it have `hide: true` after `"value": "Deceased"` in the output? – adiga Sep 03 '19 at 17:24
  • @adiga Great question, status is a field (a choice field in this case) and when you select a value, in this case `Deceaed` then we want to show the other fields: cause of death and date of death. If you then select other from cause of death we then show other cause of death. – TheWebs Sep 03 '19 at 17:38

3 Answers3

1

You're probably looking for something like

export function createHiddenFields(dependencies) {
  if (Array.isArray(dependencies)) {
    return dependencies.map(createHiddenFields);
  }
  const hiddenFields = {
    hide: true,
  };
  if (typeof dependencies == 'object' && dependencies !== null) {
    for (const key in dependencies) {
      if (key == 'affects') {
        hiddenFields.affects = createHiddenFields(dependencies.affects);
      } else {
        hiddenFields[key] = dependencies[key];
      }
    }
  }
  return hiddenFields;
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

You can do this using recursion and for...in loop and check if the value of the property is object then call the function again or if its not then add the value.

const data = {"comorbidities":[{"affects":{"malignancy_type":{"affects":{"malignancy_type_other":"malignancy_type_other"},"value":"Other"}},"value":"malignancy"},{"affects":{"heritable_syndrome_type":"heritable_syndrome_type"},"value":"heritable syndrome"}]}

function update(obj, val) {
  for (let i in obj) {
    if (typeof obj[i] == 'object') update(obj[i], val);
    else if ('affects' in obj) Object.assign(obj, val);
    else obj[i] = val
  }
}

update(data, {hide: true});
console.log(data)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • 1
    [You shouldn't use `for…in` enumerations on arrays](https://stackoverflow.com/q/500504/1048572) though, so I'd expect an extra `if (Array.isArray(obj)) …` check – Bergi Sep 03 '19 at 17:31
  • `else if ('affects' in obj) Object.assign(obj, val);` shouldn't be inside the loop. It just does the same hing for every iteration multiple times for no good reason. – Tomáš Zato Sep 05 '19 at 14:47
0

I decided to post a late answer anyway, because I see some possible flaws and gotchas in the other answers. Specifically:

  • for ... in is dangerous because it may loop over any iterable Object.prototype propertyes, which sometimes exist thanks to irresponsible developers. In general it loops over all properties including inherited ones
  • for ... in is not supposed to be used for looping over an array
  • It may be unwise to reuse the {hide: true} object. Should you later wish to alter the hide property for some entries in the tree, it would affect all that share the same object reference

So I'd instead write a longer but safer method:

function createHiddenFields(obj) {
  // ignore nulls
  if(obj == null) {
    return;
  }
  // For an array, just do the update for each object in array
  else if(obj instanceof Array) {
    for(const subObj of obj) {
      createHiddenFields(subObj);
    }
  }
  // For object, do the hidden field thing
  else if(typeof obj == "object") {
    // Replace all string values with hiddenVal
    for(const valueName of Object.getOwnPropertyNames(obj)) {
      // Do not override value nodes
      if(valueName == "value") {
        continue;
      }
      else {
        // Process sub-objects
        if(typeof obj[valueName] == "object") {
          createHiddenFields(obj[valueName]);
        }
        // Replace primitive property values
        else {
          obj[valueName] = { hide: true };
        }
      }
    }
    // add hidden field for affects
    if(typeof obj.affects == "object") {
      obj.hide = true;
    }
  }
}

demo

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778