WrathChaos / react-native-bouncy-checkbox

Fully customizable animated bouncy checkbox for React Native
https://freakycoder.com
MIT License
774 stars 59 forks source link

Select Multiple Checkboxes with one Checkbox #494

Closed aliraza944 closed 5 months ago

aliraza944 commented 5 months ago

I am trying to select all of my checkboxes by pressing the All checkbox. The problem is their state updates and corresponding color changes but the check box doesn't get checked even though the prop isChecked is true for all of them.

Here is my bare minimum code


import React, { useState, useRef } from 'react';

import Colors from '@/helpers/Colors';
import BouncyCheckbox from 'react-native-bouncy-checkbox';

import styles from './styles';

export const FiltersCheckbox = ({
  label,
  id,
  isChecked,
  disabled = false,
  handleCheckBoxChange,
}) => {
  const handleCheckedChange = (checked: boolean) => {
    handleCheckBoxChange(checked, id);
  };

  return (
    <BouncyCheckbox
      size={24}
      fillColor={Colors.CHIP_RED_BORDER}
      unfillColor={Colors.WHITE}
      text={label}
      isChecked={isChecked}
      iconStyle={styles.iconStyle}
      style={styles.container_main}
      innerIconStyle={[
        styles.innerIconStyle,
        isChecked && styles.innerIconStyle_checked,
      ]}
      textStyle={[styles.textStyle, isChecked && styles.textStyle_checked]}
      textContainerStyle={styles.container_textStyle}
      onPress={handleCheckedChange}
      disabled={disabled}
    />
  );
};

and this is the parent component

import React, { useState } from 'react';
import { View, Text } from 'react-native';
import styles from './styles';
import FiltersCheckbox from '@/components/WorkshopFilters/FiltersCheckbox';
import { Layout } from '@ui-kitten/components';

const data = [
  {
    id: 0,
    label: 'All',
    isChecked: false,
    value: '',
  },
  {
    id: 1,
    label: 'Pre-Listing',
    isChecked: false,
    value: 'PreListing',
  },
  {
    id: 2,
    label: 'Offer Exclusive',
    isChecked: false,
    value: 'OfferExclusive',
  },
  {
    id: 3,
    label: 'Coming Soon',
    isChecked: false,
    value: 'ComingSoon',
  },
  {
    id: 4,
    label: 'Active Listings',
    isChecked: false,
    value: 'ActiveListing',
  },
  {
    id: 5,
    label: 'TNAS',
    isChecked: false,
    value: 'TNAS',
  },
  {
    id: 6,
    label: 'Under Contract',
    isChecked: false,
    value: 'Under contract',
  },
  {
    id: 7,
    label: 'Clear to Close',
    isChecked: false,
    value: 'Clear to close',
  },
  {
    id: 8,
    label: 'Closed',
    isChecked: false,
    value: 'Closed',
  },
  {
    id: 9,
    label: 'Cancelled',
    isChecked: false,
    value: 'Cancelled',
  },
];

export const FilterByTransactions = ({
  selectedItem,
  selectionItems,
  handleFilterUpdates,
}) => {
  const [checkBoxes, setCheckBoxes] = useState(data);

  const handleCheckBoxChange = (checked: boolean, id: number) => {
    if (id === 0) {
      const updatedCheckBoxes = checkBoxes.map(item => {
        return {
          ...item,
          isChecked: checked,
        };
      });

      setCheckBoxes(updatedCheckBoxes);
      handleFilterUpdates(
        updatedCheckBoxes.filter(item => item.isChecked === true),
        'statuses',
      );
      return;
    }

    const updatedCheckBoxes = checkBoxes.map(item => {
      if (item.id === id) {
        return {
          ...item,
          isChecked: checked,
        };
      }
      return item;
    });

    setCheckBoxes(updatedCheckBoxes);
    handleFilterUpdates(
      updatedCheckBoxes.filter(item => item.isChecked === true),
      'statuses',
    );
  };

  return (
    <View style={styles.container_main}> 
      <View style={styles.container_sub}>
        <Text style={styles.subHeading}>Listings</Text>

        <Layout style={styles.container_layout}>
          {checkBoxes.map(item => (
            <View style={styles.container_item} key={item.id}>
              <FiltersCheckbox
                label={item.label}
                id={item.id}
                isChecked={item.isChecked}
                handleCheckBoxChange={handleCheckBoxChange}
              />
            </View>
          ))}
        </Layout>
      </View>
    </View>
  );
};

Untitled video - Made with Clipchamp

I am using the react-native-bouncy-checkbox version 3.0.6

WrathChaos commented 5 months ago

Hello @aliraza944

You should use disableBuiltInState prop or please upgrade the react-native-bouncy-checkbox to version 4+ and you can directly use isChecked prop without any extra prop like disableBuiltInState or anything so you can directly control each of them separately.

WrathChaos commented 5 months ago

Hey again @aliraza944,

I made an example for you :)

Here is the repo if you wanna check it out: https://github.com/WrathChaos/react-native-bouncy-checkbox-check-all-with-one-checkbox example

Here is how you can do it with latest react-native-bouncy-checkbox version:

FilterCheckbox.tsx

import React from 'react';
import {StyleProp, ViewStyle, StyleSheet} from 'react-native';
import BouncyCheckbox from 'react-native-bouncy-checkbox';

interface FilterCheckboxProps {
  id: number;
  isChecked: boolean;
  style?: StyleProp<ViewStyle>;
  onCheckboxPress: (checked: boolean, id: number) => void;
}

const FilterCheckbox: React.FC<FilterCheckboxProps> = ({
  id,
  style,
  isChecked,
  onCheckboxPress,
}) => {
  const handleCheckboxPress = () => {
    onCheckboxPress(!isChecked, id);
  };

  return (
    <BouncyCheckbox
      style={[styles.checkbox, style]}
      isChecked={isChecked}
      onPress={handleCheckboxPress}
    />
  );
};
const styles = StyleSheet.create({
  checkbox: {
    width: 35,
    height: 35,
  },
});

export default FilterCheckbox;

App.tsx:

import React, {useState} from 'react';
import {View, StyleSheet} from 'react-native';
import FilterCheckbox from './src/FilterCheckbox.tsx';

interface AppProps {}

const data = [
  {
    id: 0,
    label: 'All',
    isChecked: false,
    value: '',
  },
  {
    id: 1,
    label: 'Pre-Listing',
    isChecked: false,
    value: 'PreListing',
  },
  {
    id: 2,
    label: 'Offer Exclusive',
    isChecked: false,
    value: 'OfferExclusive',
  },
  {
    id: 3,
    label: 'Coming Soon',
    isChecked: false,
    value: 'ComingSoon',
  },
  {
    id: 4,
    label: 'Active Listings',
    isChecked: false,
    value: 'ActiveListing',
  },
  {
    id: 5,
    label: 'TNAS',
    isChecked: false,
    value: 'TNAS',
  },
  {
    id: 6,
    label: 'Under Contract',
    isChecked: false,
    value: 'Under contract',
  },
  {
    id: 7,
    label: 'Clear to Close',
    isChecked: false,
    value: 'Clear to close',
  },
  {
    id: 8,
    label: 'Closed',
    isChecked: false,
    value: 'Closed',
  },
  {
    id: 9,
    label: 'Cancelled',
    isChecked: false,
    value: 'Cancelled',
  },
];

const App: React.FC<AppProps> = () => {
  const [checkBoxes, setCheckBoxes] = useState(data);

  const handleCheckboxPress = (checked: boolean, id: number) => {
    if (id === 0) {
      setCheckBoxes(
        checkBoxes.map(item => ({
          ...item,
          isChecked: checked,
        })),
      );
      return;
    }

    setCheckBoxes(
      checkBoxes.map(item =>
        item.id === id ? {...item, isChecked: checked} : item,
      ),
    );
  };

  return (
    <View style={styles.container}>
      {checkBoxes.map(item => (
        <FilterCheckbox
          id={item.id}
          key={`${item.id}`}
          isChecked={item.isChecked}
          onCheckboxPress={handleCheckboxPress}
        />
      ))}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  checkbox: {
    width: 35,
    height: 35,
  },
});

export default App;

So, simply you can use isChecked prop to control all of them or one by one with:


  const handleCheckboxPress = (checked: boolean, id: number) => {
    if (id === 0) {
      setCheckBoxes(
        checkBoxes.map(item => ({
          ...item,
          isChecked: checked,
        })),
      );
      return;
    }

    setCheckBoxes(
      checkBoxes.map(item =>
        item.id === id ? {...item, isChecked: checked} : item,
      ),
    );
  };
WrathChaos commented 5 months ago

You can even check the FAQ part, I updated it

https://github.com/WrathChaos/react-native-bouncy-checkbox/tree/master?tab=readme-ov-file#faq

aliraza944 commented 5 months ago

thanks it worked