1

I want to add a conditional object inside an array of objects. If the condition is not met, I want it as if that object is not there AT ALL, while keeping the other objects as they are. Consider the following:

const CardBuildingBlock: FC = () => {
    const type = 'typeA';

    const typesOfCards = [
      {name: 'Card A'
      size: 'Medium'
      action: 'make'},

      {name: 'Card B'
      size: 'Small'
      action: 'break'},

      {name: 'Card C'
      size: 'Large'
      action: 'build'},

//I tried doing the following but it doesn't work

      type == 'typeA' ? null : {
      name: 'Card A'
      size: 'Medium'
      action: 'make'},
    ];


    return(
      typeOfCards.map(({name, size, action}) => (
        <BuildCard 
          name = {name}
          size = {size}
          action = {action}
        />
    )
)};

Please Help.!!!

Thanks for the help.

3
  • I'm not 100% sure on your intentions, but it sounds like you want to filter the array before you map it Commented Nov 24, 2021 at 21:06
  • don't hold null or undefined values inside the array. remove them or just don't add them Commented Nov 24, 2021 at 21:12
  • why dont you do it after the array creation. After you create typesOfCards do the conditional part. Commented Nov 24, 2021 at 21:13

3 Answers 3

2

From what I understood, you want to filter away all the elements of the array given a condition. What I would do is adding a new key to the object specifying if it should be displayed, and then filter & map.

const typesOfCards = [
  { name: "Card A", size: "Medium", action: "make", type: "typeA" },
  ...
];
return typesOfCards.filter(card => card.type === "typeA").map(({ name, size, action }) => (
    <BuildCard name={name} size={size} action={action} />
  ));
Sign up to request clarification or add additional context in comments.

5 Comments

return typesOfCards.filter(card => card.type === "typeA").map(({ name, size, action }) => ( <BuildCard name={name} size={size} action={action} /> )); when you wrote card => card.type ... did you mean typesOfCards => typesOfCards.type? Or did you mean to create a new variable inside filter?
I added the field type to all the cards. So all the cards should have a field type with the value typeA, typeB or whatever. This way, when you filter, you can use that field to remove all those that are not of a given type. I could have named it filter(typeOfCard => typeOfCard.type... but it is only the name of the variable
I understand it now. thanks, Robert. Another followup: how do I filter conditionally? How can I have cards a,b & c show up when type == 'typeA', but only have cards a & c when type == 'typeB'?
if type=='typeA' you want to show both a, b and c... that means I wouldn't use the filter because you want all.
If type=='typeB' you want to show only a and c... Then I'd do filter(card => card.type === 'typeA' || card.type === 'typeC). Note that I'm using the new field type as a helper so that I know how to filter the cards. Maybe depending on your business rules you can have another filter
2

Easiest way here would be to concat new element to an array. In case condition is true, you will concat new element. Consider this examples:

// using if statement
const type = "typeA";

let additionalCardOfTypeA = {
  name: "Card A",
  size: "Medium",
  action: "make",
};

let typesOfCards = [
  { name: "Card A", size: "Medium", action: "make" },
  { name: "Card B", size: "Small", action: "break" },
  { name: "Card C", size: "Large", action: "build" },
];

if (type === "typeA") {
  typesOfCards = typesOfCards.concat(additionalCardOfTypeA);
}
// using ternary operator
const type = "typeA";

let additionalCardOfTypeA = {
  name: "Card A",
  size: "Medium",
  action: "make",
};

let typesOfCards = [
  { name: "Card A", size: "Medium", action: "make" },
  { name: "Card B", size: "Small", action: "break" },
  { name: "Card C", size: "Large", action: "build" },
].concat(
  type === "typeA"
    ? additionalCardOfTypeA 
    : []
);

Edit

To insert new element in particular place you will have to create additional arrays. First, find a place for your element. Then, create an array that have everything before said index in original, and array that have everything from index to an end. Then concatenate start, new element and end into final array.

const type = "typeA";

let additionalCardOfTypeA = {
  name: "Card A",
  size: "Medium",
  action: "make",
};

let typesOfCards = [
  { name: "Card A", size: "Medium", action: "make" },
  { name: "Card B", size: "Small", action: "break" },

  { name: "Card C", size: "Large", action: "build" },
];

if (type === "typeA") {
  let indexForNewElement = getSomehowIndex();
  // Getting everything before index
  let head = typesOfCards.slice(0, indexForNewElement);
  // Getting everything after index
  let tail = typesOfCards.slice(indexForNewElement);
  typesOfCards = head.concat(additionalCardOfTypeA).concat(tail);
}

5 Comments

you mean push rather than concat, right? (At least in your first example. Your second will work but concating an empty array to do nothing also feels a bit strange.)
I agree. push is a better way to go here, IMO. but how would I use push if I wanted that object to be on a specific index inside the array. For example, I want Card B to be executed right after card A if/when the condition is true (it should either show up between card A and C or it shouldn't show up at all). using push would just add it at the end. Is there a way to do this using push?
No, I mean concat. concat will create new array, so there is no chances that initial data will be mutated. In this particular example all data colocated and new array created on every render, but if initial array comes from props or some other place, you can't use push and mutate it. Using concat from the start allows you move initial array around without worrying about immutability. Using empty array in concat indeed may seem strange, but it is just for the sake of ternary operator, like in initial code. I'd go with if statement personally.
I'll add example with adding element into arbitrary place into answer
Apologies, I was under the impression that concat only worked if the argument was an array, but having consulted MDN more deeply (and tried it in the console), I see that concat instead of push will work fine. Thanks for teaching me something I didn't know about JS :)
1

Maybe a push would be useful in that case:

type === 'typeA' && typesOfCards.push({
      name: 'Card A'
      size: 'Medium'
      action: 'make'}
)

maybe you might want to include that within a function and it should return the typesOfCards array

3 Comments

Awesome. I actually could use push, but in some cases, I will require the object to be at a specific index. For example, I want Card B to be executed right after card A if/when the condition is true. using push would just add it at the end. Is there a way to do this.
There are several approaches However my approach would be, add an id key to every object and then use the .sort() method So if you push a new object, it will be reordered within the array
that sounds like it will work, thanks a lot David

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.