Bahu
Bahu

Reputation: 1596

ReactNative: Custom CheckBox for both Android and iOS

As said here <checkBox/> is only possible for android but i want to implement single code for both android and iOS (without using any node packages). For this i'm proceeding with views as below

import React, { Component } from 'react';
import { Platform, View, TouchableOpacity } from 'react-native';

export default class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      checkSelected: 1

    }
  }


  checkClick(id) {
    this.setState({
      checkSelected: id
    })


  }


  render() {

    const products = [{
      id: 1
    },
    {
      id: 2
    },
    {
      id: 3
    }];

    return (
      products.map((val) => {
        return (
          <TouchableOpacity key={val.id} onPress={this.checkClick.bind(this, val.id)}>
            <View style={{
              height: 24,
              width: 24,
              border: 12,
              borderWidth: 2,
              borderColor: '#000',
              alignItems: 'center',
              justifyContent: 'center',
            }}>
              {

                val.id == this.state.checkSelected ?


                  <View style={{
                    height: 12,
                    width: 12,
                    border: 6,
                    backgroundColor: '#000',
                  }} />
                  : null

              }
            </View>
          </TouchableOpacity>
        )
      })
    );
  }
}

This output will be like this

enter image description here

This approach is like RadioButton but i want to follow the <View/> approach for CheckBox also. For this i've implemented like this

import React, { Component } from 'react';
import { View, TouchableOpacity } from 'react-native';

export default class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      checkSelected: []
    }
  }


  checkClick(id) {
    let todos = [...this.state.checkSelected];   //creating the copy

    //adding new data
    todos.push({
      checkId: id
    });

    //updating the state value
    this.setState({ checkSelected: todos }, () => {
      alert('state: ' + JSON.stringify(this.state.checkSelected));
    });

  }


  render() {

    const products = [{
      id: 1
    },
    {
      id: 2
    },
    {
      id: 3
    }];

    return (
      products.map((val) => {
        return (
          <TouchableOpacity key={val.id} onPress={this.checkClick.bind(this, val.id)}>
            <View style={{
              height: 24,
              width: 24,
              border: 12,
              borderWidth: 2,
              borderColor: '#000',
              alignItems: 'center',
              justifyContent: 'center',
            }}>
              {

                this.state.checkSelected.map((checkIds) => {
                  {
                    checkIds.checkId == val.id ?
                      <View style={{
                        height: 12,
                        width: 12,
                        border: 6,
                        backgroundColor: '#000',
                      }} />
                      : null

                  }
                })

              }
            </View>
          </TouchableOpacity>
        )
      })
    );
  }
}

In this approach i'm storing clicked id's in state and trying to select all checkboxes which id's are in state but i'm unable to do that. Can any one suggest me to select multiple check boxes.

Upvotes: 0

Views: 7644

Answers (2)

Jeff Gu Kang
Jeff Gu Kang

Reputation: 4879

Solution

  1. Make new CheckBox component.
  2. Call CheckBox components with right props.
  3. Change your state value depending on CheckBox's clicked prop.

import React, { Component } from 'react';
import { View, TouchableOpacity } from 'react-native';

class CheckBox extends Component {
  constructor(props) {
    super(props);
    this.state = {isCheck: false};
  }

  checkClicked = async () => {
    await this.setState(prevState => ({
      isCheck: !prevState.isCheck,
    })); // setState is async function.

    // Call function type prop with return values.
    this.props.clicked && this.props.clicked(this.props.value, this.state.isCheck);
  }

  render() {
    return (
      <TouchableOpacity onPress={this.checkClicked} style={this.props.style}>
        <View style={{
          height: 24,
          width: 24,
          borderWidth: 2,
          borderColor: '#000',
          alignItems: 'center',
          justifyContent: 'center',
        }}>
          <View style={{
            height: 12,
            width: 12,
            backgroundColor: this.state.isCheck ? '#000' : '#FFF',
          }} />
        </View>
      </TouchableOpacity>
    )
  }
}


const products = [
  {
    id: 1
  },
  {
    id: 2
  },
  {
    id: 3
  }
];

export default class CheckBoxScreen extends Component {
  constructor(props) {
    super(props);
    this.state = {
      checkSelected: [],
    }
  }

  toggleCheckBox = (id, isCheck) => {
    let { checkSelected } = this.state;
    if (isCheck) {
      checkSelected.push(id);
    } else { // remove element
      var index = checkSelected.indexOf(id);
      if (index > -1) {
        checkSelected.splice(index, 1);
      }
    }

    this.setState({ checkSelected });

    alert(this.state.checkSelected); // logging
  }

  render() {
    const checkboxs = products.map(({id}) =>
      <CheckBox style={{marginTop: 50,}}key={id} value={id} clicked={(id, isCheck) => this.toggleCheckBox(id, isCheck)}></CheckBox>
    )

    return (
      <View style={{flex: 1, alignItems: 'center'}}>
        {checkboxs}
      </View>
    );
  }
}

It will work and you can use my example to other ways what you want.

Upvotes: 3

angelos_lex
angelos_lex

Reputation: 1661

In a different soluion, i would recommend to make a checkbox component , which will have properties id and onCheckBoxValueChange. Both will take initial values from parent component, and on every change, the state of local component will change, returning a callback with the id of the selected.

Child:

constructor(props) {
 super(props);
 this.state = {
   value: this.props.value
 };
}

onCheckBoxValueChange(id) {
  this.setState({ value: !this.state.value });
  this.props.onCheckBoxValueChange(id, !this.state.value);
}

render() {
 return (
   <ViewStyledAsCheckBox
    style={styles.checkBox}
    isChecked={this.state.value}
    onPress={() => this.onCheckBoxValueChange(this.props.id)}
   />

Parent will call child component like this:

<CheckBoxComponent
  id={1}
  onCheckBoxValueChange={(id, value) =>
  this.doSomethingWithChangedValueInThisSpecificChekbox(id, value)
  }
/>
<CheckBoxComponent
  id={2}
  onCheckBoxValueChange={(id, value) =>
  this.doSomethingWithChangedValueInThisSpecificChekbox(id, value)
  }
/>

Let me know if this works for you or want more information as this is more of a template than real implementation

Upvotes: 0

Related Questions