wix / react-native-calendars

React Native Calendar Components 🗓️ 📆
MIT License
9.56k stars 2.96k forks source link

Cannot toggle checkbox inside Item using agenda #1038

Closed cmilios closed 4 years ago

cmilios commented 4 years ago

Description

I am trying to make a checkbox item inside of each item of the agenda. I want to change the item property and rerender Agenda everytime a press the checkbox of each item.

Expected Behavior

I am trying to use setState after I change the property (false/true) of the item pressed and re-set it as a new list of items in state but agenda does not rerender itself as it should

Observed Behavior

set State does not rerender agenda even when the items filling agenda are used from state.

Environment

react-native-calendars@1.220.0 react-native@0.61.4

Reproducible Demo

`import React, { Component } from 'react'; import { View, StyleSheet } from 'react-native'; import colors from '../constants/colors' import {Agenda} from 'react-native-calendars'; import { Container, Header, Content, Card, CardItem, Text, Right ,Body, CheckBox } from 'native-base';

export default class Home extends Component {

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

toggleIcon(itemc){
    let stItem = this.state.items
    for (let prop in stItem){
        if (Object.prototype.hasOwnProperty.call(stItem, prop)) {
            for(let i=0; i<stItem[prop].length; i++){
                if(stItem[prop][i].id==itemc.id){
                    itemc.state = !itemc.state
                    stItem[prop][i]= itemc
                    this.setState({items: stItem})
                }

            }
        }
    }
}

timeToString(time) {
    const date = new Date(time);
    return date.toISOString().split('T')[0];
  }

loadItems(items) {
    setTimeout(() => {
        if(items==null){
            let items= {
                '2019-01-10': [{id:1,type:"beard",username:"cmilios", time: 1, state: false}],
                '2019-01-12': [{id:2,type:"beard",username:"cmilios", time: 2, state: true}],
                '2019-01-13': [{id:3,type:"beard",username:"cmilios", time: 3, state: true}],
                '2019-01-14': [{id:4,type:"beard",username:"cmilios", time: 4, state: false}],
                '2019-01-15': [{id:5,type:"beard",username:"cmilios", time: 5, state: true}],
                '2019-01-16': [{id:6,type:"beard",username:"cmilios", time: 6, state: true}],
                '2019-01-17': [{id:7,type:"beard",username:"cmilios", time: 7, state: true}],
                '2019-01-18': [{id:8,type:"beard",username:"cmilios", time: 8, state: true}],
                '2019-01-19': [{id:9,type:"beard",username:"cmilios", time: 9, state: true}],                            
                '2019-01-11': [{id:10,type: "hair",username:"cc", time: 3, state: true},{id:11,type: "hair",username:"cmilaaios" ,time: 4, state: true}]
            }

        }

        this.state.items = items
      console.log(this.state.items);
      const newItems = {};
      Object.keys(this.state.items).forEach(key => {newItems[key] = this.state.items[key];});
      this.setState({
        items: newItems
      });
    }, 1000);

  }

  renderItem(item) {
    return (
        <Card>
        <CardItem header button onPress={() => alert("This is Card Header")}>
            <Text style={{marginRight: 10}}>{item.id}</Text>
            <Body>
                <Text>
                    Username: {item.username}
                </Text>
                <Text>
                    Type: {item.type}
                </Text>
            </Body>
            <CardItem footer >
                <CheckBox checked={item.state} onPress={()=>this.toggleIcon(item)}/>

            </CardItem>
        </CardItem>

    </Card>
    );
  }

  renderEmptyDate() {
    return (
      <View style={styles.emptyDate}><Text>This is empty date!</Text></View>
    );
  }

  rowHasChanged(r1, r2) {
    return r1.id !== r2.id;
  }

render() {

    return (

                <Agenda style={{marginTop: 20}}

                // the list of items that have to be displayed in agenda. If you want to render item as empty date
                // the value of date key kas to be an empty array []. If there exists no value for date key it is
                // considered that the date in question is not yet loaded
                items={this.state.items}
                loadItemsForMonth={this.loadItems.bind(this)}
                onCalendarToggled={(calendarOpened) => {console.log(calendarOpened)}}
                // callback that gets called on day press
                onDayPress={(day)=>{console.log('day pressed')}}
                // callback that gets called when day changes while scrolling agenda list
                onDayChange={(day)=>{console.log('day changed')}}
                // initially selected day
                selected={'2019-01-10'}
                firstDay={1}

                renderItem={this.renderItem.bind(this)}
                renderEmptyDate={this.renderEmptyDate.bind(this)}
                rowHasChanged={this.rowHasChanged.bind(this)}
                // specify how each item should be rendered in agenda

                // // specify how each date should be rendered. day can be undefined if the item is not first in that day.
                // renderDay={(day, item) => {return (<View style={this.styles.emptyDate}><Text>{item.day}</Text></View>);}}
                // specify how empty date content with no items should be rendered

                // specify what should be rendered instead of ActivityIndicator
                renderEmptyData = {() => {return (<View><Text>No Data</Text></View>);}}
                //specify your item comparison function for increased performance

                onRefresh={() => console.log('refreshing...')}

                theme={{
                    backgroundColor: colors.primaryColor,
                    calendarBackground: colors.primaryDarkColor,
                    textSectionTitleColor: colors.secondaryColor,
                    selectedDayBackgroundColor: colors.primaryLightColor,
                    selectedDayTextColor: '#000',
                    todayTextColor: '#00adf5',
                    dayTextColor: colors.secondaryColor,
                    textDisabledColor: '#d9e1e8',
                    dotColor: colors.secondaryDarkColor,
                    selectedDotColor: colors.secondaryDarkColor,
                    arrowColor: 'orange',
                    monthTextColor: colors.secondaryColor,
                    agendaKnobColor: colors.secondaryColor,

                    textDayFontWeight: '400',
                    textMonthFontWeight: 'bold',
                    textDayHeaderFontWeight: '400',
                    textDayFontSize: 16,
                    textMonthFontSize: 14,
                    textDayHeaderFontSize: 12
                }}

                />

            )
}
styles = StyleSheet.create({
    item: {
      backgroundColor: 'white',
      flex: 1,
      borderRadius: 5,
      padding: 10,
      marginRight: 10,
      marginTop: 17
    },
    titleText:{
        fontSize: 20,
        fontWeight: 'bold',

    },

    card:{
        backgroundColor: colors.secondaryColor,

    }
  });

} const styles = StyleSheet.create({ item: { backgroundColor: 'white', flex: 1, borderRadius: 5, padding: 10, marginRight: 10, marginTop: 17 }, emptyDate: { height: 15, flex:1, paddingTop: 30 } });`

fairhat commented 4 years ago

your rowHasChanged() func compares r1.id !== r2.id you want to update your view on r1.state though

r1 !== r2 should work in your case

chenei commented 4 years ago

Is it still relevant?