Oliver D
Oliver D

Reputation: 2889

How Can I Filter Array of object in same property?

I have a Product Options "Color, Size, etc" And as we know user can select one thing from the option "selected just red color from Colors", in this time I ad the selected one the separate Array "All Option user selected" but the issue is the user can add duplicated options in the same filed "e.g. Color" So how can I solve this issue? The final Thing should be: One thing from separate Option For Example

SelectedOptions = [
      { name:"red",id:88,optionType:"Color"},
      { name:"XL",id:22,optionType:"Size"},
      ....
    ]

But What I go now

SelectedOptions = [
          { name:"red",id:88,optionType:"Color"},
          { name:"green",id:87,optionType:"Color"},
          { name:"XL",id:22,optionType:"Size"},
          { name:"M",id:22,optionType:"Size"},
          ....
        ];

I know that's because I push any selected one to the SelectedOptions Array, I'm trying to solve it by checking the optionType but I did not get any good idea

options

Code snippet

 const [selectedIndexColor, setSelectedIndexColor] = useState<
    number | undefined
  >();
  const [selectedIndexText, setSelectedIndexText] = useState<number | null>();
  const [selectedIndexImage, setSelectedIndexImage] = useState<number | null>();
  interface ManipulateValueOptionProp extends valueOptionProp {
    optionType: string;
  }
  const [allOptions, setAllOptions] = useState<ManipulateValueOptionProp[]>([]);

const renderValue = (value: valueOptionProp, type: string) => {
    const selectedColor = selectedIndexColor === value.id;
    const selectedText = selectedIndexText === value.id;
    const selectedImage = selectedIndexImage === value.id;
    switch (type) {
      case 'text': {
        return (
          <View
            style={[
              styles.selectedText,
              {backgroundColor: selectedText ? 'black' : 'transparent'},
            ]}>
            <Text
              style={{
                textAlign: 'center',
                color: selectedText ? 'white' : 'black',
                fontSize: 12,
              }}>
              {value.name_en}
            </Text>
          </View>
        );
      }
      case 'Color': {
        return (
          <>
            <View
              // @ts-ignore
              // eslint-disable-next-line react-native/no-inline-styles
              style={{
                width: 53,
                height: 53,
                backgroundColor: value.display_value,
              }}
            />
            {selectedColor ? (
              <View style={styles.selectedColor}>
                <CheckmarkIcon color="black" />
              </View>
            ) : null}
          </>
        );
      }
      case 'images': {
        return (
          <>
            <Image
              // @ts-ignore
              source={{uri: value.display_value}}
              // eslint-disable-next-line react-native/no-inline-styles
              style={{width: 53, height: 53, backgroundColor: '#0f4c7f'}}
            />
            {selectedImage ? (
              <View style={styles.selectedColor}>
                <CheckmarkIcon />
              </View>
            ) : null}
          </>
        );
      }
      default: {
        return null;
      }
    }
  };



{item.options.map((option) => {
        return (
          <View style={styles.optionsBox}>
            <Text style={styles.optionTxt}>{option.label_en}</Text>
            <View style={{flexDirection: 'row'}}>
              {option.values.map((value: valueOptionProp) => {
                return (
                  <ScalePressable
                    key={`${option.id}${value.id}`}
                    onPress={() => {
                      option.type === 'Color' &&
                        setSelectedIndexColor(value.id);
                      option.type === 'text' && setSelectedIndexText(value.id);
                      option.type === 'images' &&
                        setSelectedIndexImage(value.id);

                      if (
                        !allOptions.some(
                          (alreadyExist) => alreadyExist.id === value.id,
                        )
                      ) {
                        setAllOptions((options) => [
                          ...options,
                          {...value, optionType: option.type},
                        ]);
                      }
                    }}>
                    <View style={styles.values}>
                      {renderValue(value, option.type)}
                    </View>
                  </ScalePressable>
                );
              })}
            </View>
          </View>
        );
      })}

Upvotes: 0

Views: 85

Answers (2)

Drew Reese
Drew Reese

Reputation: 202854

Seems to me you just need to remove deselected options from allOptions array when the user presses that same filter option.

onPress={() => {
  option.type === 'Color' && setSelectedIndexColor(value.id);
  option.type === 'text' && setSelectedIndexText(value.id);
  option.type === 'images' && setSelectedIndexImage(value.id);

  if (allOptions.some(option => option.type === value.type)) {
    setAllOptions(options => options.filter(option => option.type !== value.type));
  } else {
    setAllOptions((options) => [
      ...options,
      { ...value, optionType: option.type },
    ]);
  }
}}

Upvotes: 0

greenBox
greenBox

Reputation: 552

Here is one possible solution. You may consider creating a new array by removing all options with the same option type as the new option and then adding the new option into the new array.

let selectedOptions = [
  { name: 'red', id: 88, optionType: 'Color' },
  { name: 'XL', id: 22, optionType: 'Size' },
];

let newOption = { name: 'green', id: 87, optionType: 'Color' };

selectedOptions = [
  ...selectedOptions.filter(
    option => option.optionType != newOption.optionType
  ),
  newOption,
];

Upvotes: 1

Related Questions