Shruti Nair
Shruti Nair

Reputation: 2034

react native ListView datasource not updating

i'm trying to update a datasource and i have checked the below url

https://github.com/facebook/react-native/issues/4104 https://github.com/mobxjs/mobx/issues/569

i tired creating a new array and then updating it but i'm not sure how to update the datasource.

On change of the checkbox i'm updating the object and assigning it to the datatsource, but the checkbox is not updating.

Below is the code i have tried.

constructor

constructor() {
            super();
            const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});

            this.state = {
              modalVisible: false,
              todoText:'',
              todoListArray:[],
              dataSource: ds

            };

       }

Listview

 <ListView
dataSource={this.state.dataSource}
        renderRow={this.generateRow.bind(this)}
        /> 

generateRow=(rowData, sectionID, rowID, highlightRow) => {

     return (
          <View style={styles.listItem}>
              <CheckBox 
                  label='' 
                  checked={rowData.isCompleted} 
                  onChange={() => {this.changeisCompleted(this,rowID)}}
              />
              <Text style={styles.listItemText}>{rowData.text}</Text>

          </View>

          );

    }

/*When Checkbox is clicked*/
    changeisCompleted=(rowData,rowId)=>{

       var newDs = [];
       newDs = this.state.todoListArray.slice();
       newDs[rowId].isCompleted =!newDs[rowId].isCompleted;
       alert(JSON.stringify(newDs));
       this.setState({
          dataSource: this.state.dataSource.cloneWithRows(newDs)
       })


    }

/*adding new item to listView*/
    addTodo = () => {
              var todoObj={
                "text":this.state.todoText,
                "isCompleted":false
              }
              this.state.todoListArray.push(todoObj);
              this.closeModal();
              this.setState({todoText: ''});
               this.setState({
                  dataSource: this.state.dataSource.cloneWithRows(this.state.todoListArray)
               })
            }

adding the entire file:

/**
     * Sample React Native App
     * https://github.com/facebook/react-native
     * @flow
     */

 import React, { Component } from 'react';
 import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ToolbarAndroid,
  Modal,
  Button,
  TextInput,
  Image,
  ListView,
  TouchableHighlight

} from 'react-native';

import CheckBox from 'react-native-checkbox';

{/*import AddToDoModal from './src/components/AddTodoModal.js';*/}


export default class FirstReactNativeApp extends Component {

  constructor() {
        super();
        const ds = new ListView.DataSource({rowHasChanged: (row1, row2) => row1 !== row2});

        this.state = {
          modalVisible: false,
          todoText:'',
          todoListArray:[],
          dataSource: ds,

        };

   }
componentDidMount = () => function() {

}

openModal = () => {
  this.setState({modalVisible: true});

}
closeModal = () => {
  this.setState({modalVisible: false});
}
setModalVisible=(visible) =>{
  this.setState({modalVisible: visible});
}
changeisCompleted=(rowData,rowId)=>{

   var newDs = [];
   newDs = this.state.todoListArray.slice();
   newDs[rowId].isCompleted =!newDs[rowId].isCompleted;
   newDs[rowId].text ="Changed";
   alert(JSON.stringify(newDs));
   //this.state.todoListArray=newDs;
   //alert("listArray=="+JSON.stringify(this.state.todoListArray))
   this.setState({
      todoListArray:newDs,
      dataSource: this.state.dataSource.cloneWithRows(newDs)
   })


}
addTodo = () => {
  var todoObj={
    "text":this.state.todoText,
    "isCompleted":false
  }
  this.state.todoListArray.push(todoObj);
  this.closeModal();
  this.setState({todoText: ''});
   this.setState({
      dataSource: this.state.dataSource.cloneWithRows(this.state.todoListArray)
   })
}
generateRow=(rowData, sectionID, rowID, highlightRow) => {


    return (
      <View style={styles.listItem}>
          <CheckBox 
              label='' 
              checked={rowData.isCompleted} 
              onChange={() => {this.changeisCompleted(this,rowID)}}
          />
          <Text style={styles.listItemText}>{rowData.text}</Text>

      </View>

      );

}

render() {
  return (
    <View>
          <ToolbarAndroid
          style={styles.toolbar}
          title="ToDo List"
          actions={[{title: 'Add', icon: require('./img/add.png'), show: 'always'}]}
          onActionSelected={this.openModal}
          />

          <ListView
          dataSource={this.state.dataSource}
          renderRow={this.generateRow.bind(this)}
          />



          <Modal
            animationType={"none"}
            transparent={false}
            visible={this.state.modalVisible}
            onRequestClose={() => {alert("Modal has been closed.")}} >

              <View style={styles.container}>
                 <View style={styles.modalContent}>

                        {/*this is icon button*/}
                      <TouchableHighlight style={{justifyContent:'flex-end',flexDirection:'row'}} onPress={this.closeModal}>
                          <Image
                              style={styles.closeButton}
                              source={require('./img/close.png')}
                          />
                      </TouchableHighlight>
                      <Text style={{textAlign:'center',marginBottom:30}}>Add New ToDo</Text>
                      <TextInput
                          style={{height: 40, borderColor: 'gray', borderWidth: 1,marginBottom:10}}
                          placeholder='Enter ToDo'
                          onChangeText={(todoText) => this.setState({todoText})}
                          value={this.state.todoText}
                      />
                     <Button 
                           onPress={()=> {this.addTodo()}}
                            title='Add ToDo'
                            color='#1e90ff'/>


                   </View>
              </View>
          </Modal>

  </View>
  );
}

}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#000000',
    opacity:0.8
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
  toolbar: {
    height:55,
    backgroundColor: '#1e90ff',
  },
  modal: {
    height:50,
    marginVertical:22,
  },
  modalContent: {
    backgroundColor: '#ffffff',
    height:300,
    width:300,
    borderRadius:3,
    paddingVertical:10,
    paddingHorizontal:20,

  },
  closeButton: {
    height:30,
    width:30,
  },
  listItem: {
    backgroundColor: '#ffffff',
    paddingLeft:10,
    height:50,
    borderBottomWidth:1,
    borderColor: '#000000',
    flex:1,
    flexDirection:'row',
    alignItems:'center',
  },
  listItemText: {

  fontSize:20,

  }
});

AppRegistry.registerComponent('FirstReactNativeApp', () => FirstReactNativeApp);

Upvotes: 0

Views: 1122

Answers (2)

Shruti Nair
Shruti Nair

Reputation: 2034

So after a lot of reading and changes the listview is now updating. According to this post

Changes the ds declaration to:

this.ds = new ListView.DataSource({rowHasChanged: (row1, row2) => row1 !== row2});

So changed my changeisComplete method

changeisCompleted=(rowData,rowId)=>{

           var newDs = [];
           newDs = this.state.todoListArray.slice();
           newDs[rowId].isCompleted =!newDs[rowId].isCompleted;


           this.setState({
                  dataSource: this.ds.cloneWithRows(this.state.todoListArray),
                  todoListArray:newDs
               })


            }

I'm not sure if this is the right way to do this,but anyway it works and now the checkbox is getting changed

Thanks

Upvotes: 1

sebastianf182
sebastianf182

Reputation: 9978

You have two problems. First, you are setting the datasource to the result of the cloning. Just use {this.state.dataSource}:

dataSource={this.state.dataSource.cloneWithRows(this.state.todoListArray)}

because you are setting the DS result and not linking the Datasource. Also, you don't need the double data in the state (The array and also the datasource).

And the second and most important, you are not actually setting the state. Only in the constructor you can set it like this: this.state.

After that, you can only set it like this:

this.setState({dataSource: this.state.dataSource.cloneWithRows(updatedArray)});

Upvotes: 0

Related Questions