0

Validate whether all Object.keys() of the parameter are equal to the specific keys (JavaScript)

I am new here. I'm learning web programming, and now I'm a bit stuck with Javascript. I want to validate that, when a new object is added to an array, it has all the required keys. I have shared below an array object, an example object with all the keys, and an object that does not have all the required keys. I tried to use Object.keys() to compare the keys of an array object, with the object to be input. However, unfortunately both objects that have all the keys and objects that do not have all the keys are taken as incomplete. I cannot add any new objects, even though they have all the keys that the other objects in the array have. Does anyone know where I am going wrong? I would be very grateful for help.

Thanks and best regards to all!

Francisco

Code:

let pokemonRepository = (function () {

...

pokedex = [
  {
      name: 'Blastoise',
      types: ['Water', 'None'],
      height: 1.6,
      weight: 85.5,
      gender: ['Male', 'Female'],
      category: 'Shellfish',
      evolutions: ['None'],
      description:
        'It crushes its foe under its heavy body to cause fainting. In a pinch, it will withdraw inside its shell.',
  },
];

function add(item) {
    if (typeof item === 'object') {

      // This is where I am failing

      if (Object.keys(item) === Object.keys(pokemonList[0])) {
        alert(
          `You have discovered a new Pokémon! "${item.name}" data has been entered into the Pokédex.`
        );
        pokemonList.push(item);
      } else {
        alert(
          `The data for the new Pokémon you are trying to add is not complete. Please verify that no fields are missing.`
        );
      }

    } else {
      alert(
        `"${item}" is not a valid Pokémon! Please check that the data type typed in is an object.`
      );
    }
}

...

})();

// Add a valid object
pokemonRepository.add({
  name: 'Wartortle',
  types: ['Water', 'None'],
  height: 1,
  weight: 22.5,
  gender: ['Male', 'Female'],
  category: 'Turtle',
  evolutions: ['Blastoise'],
  description:
  'It is recognized as a symbol of longevity. If its shell has algae on it, that Wartortle is very old.',
});

// Add a invalid object (missing data)
pokemonRepository.add({
  name: 'Bla',
  types: ['Bla', 'Bla'],
  height: 1,
  weight: 800,
});

Edit:

Thank you very much to everyone who answered me! I never thought you would see my message. I am very grateful to you. After trying for more than 2 hours to find the solution, I have managed to correct the problem thanks to your help. Thank you all! The code looks like this (I only changed the way of comparing the keys of the objects):

  function add(item) {
    if (typeof item === 'object') {

      // Changes here
      if (Object.keys(pokemonList[0]).every((key) => key in item)) {
      // Changes here
        alert(
          `You have discovered a new Pokémon! "${item.name}" data has been entered into the Pokédex.`
        );
        // Changes here (to validate)
        console.log(Object.keys(pokemonList[0]).every((key) => key in item));
        // Changes here (to validate)
        pokemonList.push(item);
      } else {
        alert(
          `The data for the new Pokémon you are trying to add is not complete. Please verify that no fields are missing.`
        );
        // Changes here (to validate)
        console.log(Object.keys(pokemonList[0]).every((key) => key in item));
        // Changes here (to validate)
      }
    } else {
      alert(
        `"${item}" is not a valid Pokémon! Please check that the data type typed in is an object.`
      );
    }
  }

Thanks to all of you wonderful people of the internet! Francisco

  • See: [How to compare arrays in JavaScript?](https://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript) – pilchard Mar 12 '21 at 18:26

4 Answers4

1

Comparing Object.keys(item) === Object.keys(pokemonList[0]) doesn't work because === does an identity comparison. If they're not literally the same array (they're not) this will never resolve to true.

You could use Array.every and in for this:

Object.keys(pokemonList[0]).every(key => key in item)

// convenience utility function to test whether
// objB has all of objA's keys:
const hasAllKeys = (objA, objB) => (
  Object.keys(objA).every(key => key in objB)
);

// a valid object
const valid = {
  name: 'Wartortle',
  types: ['Water', 'None'],
  height: 1,
  weight: 22.5,
  gender: ['Male', 'Female'],
  category: 'Turtle',
  evolutions: ['Blastoise'],
  description: 'It is recognized as a symbol of longevity. If its shell has algae on it, that Wartortle is very old.',
};

const alsoValid = {
  name: 'Foo Wartortle',
  types: ['Foo', 'Water', 'None'],
  height: 4,
  weight: 22222.5,
  gender: ['Male', 'Female'],
  category: 'Turtle',
  evolutions: ['Blastoise'],
  description: 'It is recognized as a symbol of longevity. If its shell has algae on it, that Wartortle is very old.',
};

// invalid object (missing data)
const invalid = {
  name: 'Bla',
  types: ['Bla', 'Bla'],
  height: 1,
  weight: 800,
};

console.log(hasAllKeys(valid, invalid)); // false 
console.log(hasAllKeys(valid, alsoValid)); // true
ray
  • 26,557
  • 5
  • 28
  • 27
0

You could create some sort of schema to determine what keys a new pokemon entry should have. This could be a simple array of property keys that reflect a complete object.

Then have a function which loops over each of these keys and checks if every one of them are found in the given object. Based on the result it returns true or false.

const keys = [
  'name',
  'types',
  'height',
  'weight',
  'gender',
  'category',
  'evolutions',
  'description'
];

const shouldHaveKeys = (keys, entry) => 
  keys.every(key => key in entry) && 
  keys.length === Object.keys(entry).length;
  
const wartortle = {
  name: 'Wartortle',
  types: ['Water', 'None'],
  height: 1,
  weight: 22.5,
  gender: ['Male', 'Female'],
  category: 'Turtle',
  evolutions: ['Blastoise'],
  description:
  'It is recognized as a symbol of longevity. If its shell has algae on it, that Wartortle is very old.',
};

const ekans = {
  name: 'Ekans',
  types: ['None'],
  height: 2,
};

console.log( shouldHaveKeys(keys, wartortle) );
console.log( shouldHaveKeys(keys, ekans) );
Emiel Zuurbier
  • 19,095
  • 3
  • 17
  • 32
  • This will validate if the item has a subset of the required keys. You'd want to validate in the other direction: `keys.every(key => key in entry)`. – ray Mar 12 '21 at 18:32
  • Thanks for the feedback. I do believe when checking both the keys and length of both should ensure that they have the correct properties. – Emiel Zuurbier Mar 12 '21 at 18:40
  • Yep. We're suggesting the same solution. Yours has the advantage of being explicit about what's required rather than just matching the first object. And you're ensuring an exact match with the length comparison. Wasn't clear from OP whether that was a requirement, whether extra keys are a problem. – ray Mar 12 '21 at 18:42
0

I would use something like yup to validate your object instead of manually trying to validate keys. You can require certain value to be true or simply just require all the keys.

const Yup = require('yup');

const YupSchema = Yup.object().shape({
  name: Yup.string().required('Name is required'),
  types: Yup.string().oneOf(['Water', 'None']),
  height: Yup.number().required('Height is required'),
  weight: Yup.number().required('Weight is required'),
  gender: Yup.string().oneOf(['Male', 'Female']),
  category: Yup.string().required('Category is required'),
  evolutions: Yup.string().oneOf(['Blastoise']),
  description: Yup.string().required('Description is required'),
});

try {
  const notPokemon = { name: 'John', types: 'Land' };
  YupSchema.validateSync(notPokemon);

  // This is a pokemon
} catch (err) {
  // This is not a pokemon
  console.error(err);
}
Kevin Aung
  • 803
  • 6
  • 12
0

I was trying to do this exact challenge and ended up checking the 'Object keys()' of the incoming pokemon object with 'Array includes()'

Perhaps quite unwieldy if you have lots of keys to check? ...but it worked, and hey, I learnt about 'array includes()'

function add(pokemon) {
    if (
      Object.keys(pokemon).includes('name') &&
      Object.keys(pokemon).includes('height') &&
      Object.keys(pokemon).includes('types')
    ) {
      return pokemonList.push(pokemon);
    } else {
      alert('incomplete data');
    }
  }
Nick
  • 11
  • 3