0

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>
        );
      })}
3
  • Your question/issue is difficult to understand. What exactly are you trying to filter? The selected options? The data based on the selected options? Could you also include some expected result from a sample input? Commented Feb 27, 2021 at 0:34
  • @DrewReese the case is i got a Three type of options "Color, Image, Text" as an array of object and I render the option name and its values as you see in the screenshot Now when the user selected any option "Red Color" i push this option to the All Options user selected, So the issue is when user choose Red then cancel it and choose Green under the hood I store Red before So I will Get two options in the same Type "Colors", What I want is just Select the last thing user to choose! I hope u understand me well, And if You check out the output code u will understand my issue Commented Feb 27, 2021 at 0:43
  • So basically you need to implement removing options a user has "deselected"? Commented Feb 27, 2021 at 1:11

2 Answers 2

1

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,
];

Sign up to request clarification or add additional context in comments.

2 Comments

Hmm, so we first spread all options and using filter to remove the duplicated type then add the new option? and why we should create a new array? I'm a little confused :\
The use of filter here removes all elements whose optionType is the same as newOption. The spread operator is then applied to access the elements from the result of applying filter and newOption is included in the array literal. The choice of not performing an in-place operation (i.e. push) is to align more with a functional programming approach, which increases the robustness of your code base.
0

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 },
    ]);
  }
}}

4 Comments

Sadly not work as expected it still stores the unSelected Data I selected before, btw the above answer work perfectly please take a look!, and for sure thanks for your Time Really appreciate
@OliverD Are you sure you implemented it correctly? This is a standard pattern for removing an element from a state array. The above solution unnecessarily loops over the data twice just to remove an option(s), FYI, once to remove matching "types" and a second time to copy to new array.
@OliverD Ah, I see what you mean now. I was simply extending your logic of checking the option id, but the logic should be looking at the filter option type instead. Please check again. It's actually a wash between the two solutions, both ways iterate the data twice. Only way to improve is to store your filter options in a map/object/dictionary so you get O(1) lookups, versus O(n).
yes i'm sure! and there's a syntax issue in the filter i fix it :D Check this Record Please i.imgur.com/DgN13Qf.mp4

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.