React-Native ListView: cannot read property of undefined - android

I am using SQLite as the device's database. What I am trying to basically achieve is this:
1- Give a user the ability to star his favorite "data"
2- Once the data gets saved in the db, retrieve it inside another page and insert them into a listView for the user to see at any time.
But no matter how much I try, I am always getting the same error.
Cannot read property of undefined.
The code:
import React, { Component } from 'react'
import {
View,
Text,
ListView
} from 'react-native'
var SQLite = require('react-native-sqlite-storage')
var db = SQLite.openDatabase({ name: "RHPC.db", location: "default"})
var obj;
class Schedules extends Component {
constructor(props) {
super(props)
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
this.state = {
datasource: []
}
db.transaction((tx) => {
tx.executeSql("SELECT * FROM schedules", [], (tx, res) => {
let len = res.rows.length;
if(len > 0) {
for(let i = 0; i < len; i++) {
var obj = [{id: res.rows.item(i)["id"], title: res.rows.item(i)["title"]}]
}
this.setState({
datasource: obj
})
} else {
console.log("empty")
}
})
}, (err) => {
console.log("error: " + JSON.stringify(err))
})
}
_renderRow(rowData) {
return(
<View>
<Text key={rowData.id}>
{rowData.title}
</Text>
</View>
)
}
render() {
console.log(this.state.datasource);
return(
<View style={{marginTop: 150}}>
<ListView
dataSource={this.state.datasource}
renderRow={this._renderRow.bind(this)}
/>
</View>
);
}
}
const styles = {
}
export default Schedules;
When I try to console.log the dataSource state:
0: Object
id: 2
title: "Session 1: Transition from Humanitarian Assistance to Rebuilding Health & Health Systems."
So in other words it looks like it's working but not 100%? Because I do have two rows inside that table and it's only retrieving the last one. Is this the cause of the undefined issue?

You use ListView in a wrong way, you create new dataSource in constructor (ds) and not assign it anywhere, checkout example in documentation: https://facebook.github.io/react-native/docs/listview.html
It should be:
constructor(props) {
super(props)
this.state = {
dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}),
}
}
And in setState make something like this:
this.setState({
datasource: this.state.dataSource.cloneWithRows(obj)
})
Edit:
And in your for loop you should have:
var obj = [];
for(let i = 0; i < len; i++) {
obj.push({id: res.rows.item(i)["id"], title: res.rows.item(i)["title"]});
}

Related

Get average of values in a field in realm react native

This is telling me 'Can't find variable: gpa'
It is also saying unresolved variable Double. I want to fetch all the values submitted in a particular field and compute the average. The average is to be displayed in an alert box. The code is in a function named dbtotal below.
class MainActivity extends Component {
static navigationOptions =
{
title: 'MyGPA',
};
GoToSecondActivity = () =>
{
this.props.navigation.navigate('Second');
};
constructor() {
super();
this.state = {
Student_Name : '',
Semester : '',
GPA : ''
};
realm = new Realm({
schema: [{name: 'CalcGP',
properties:
{
student_id: {type: 'int', default: 0},
student_name: 'string',
semester: 'int',
gpa: 'double'
}
}]
});
}
add_Student = () => {
realm.write(() => {
let ID = realm.objects('CalcGP').length + 1;
realm.create('CalcGP', {
student_id: ID,
student_name: this.state.Student_Name,
semester: this.state.Semester,
gpa : this.state.GPA,
});
});
Alert.alert("Details Added Successfully.");
};
let mydata = realm.objects('CalcGP');
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(mydata),
};
}
GoToEditActivity (student_id, student_name, semester, gpa) {
this.props.navigation.navigate('Third', {
ID : student_id,
NAME : student_name,
CLASS : semester,
SUBJECT : gpa,
});
}
dbtotal() {
let cgpa: Double = realm.objects('CalcGP').avg(gpa) ;
Alert.alert(cgpa);
}
<TouchableOpacity onPress={this.dbtotal} activeOpacity={0.7} style={styles.button} >
<Text style={styles.TextStyle}> CALCULATE </Text>
</TouchableOpacity>
avg(gpa) should be avg('gpa').
And let cgpa: Double = can be let cgpa =.
This is working fine
`let average = realm.objects('CalcGP').avg('gpa');
this.state = {
aver: Alert.alert(Your CGPA is + average.toString())
};`

passProps throws 'Error calling RCTEventEmiter.receiveTouches' (react-native-navigation)

I'm trying to pass some data to a modal screen with react-native-navigation pacakage 1.1.65 (https://github.com/wix/react-native-navigation)
I have two cases :
First one
export default class SearchTab extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dicoDataSource: ds.cloneWithRows(realm.objects('User')),
searchText:'',
data:[]
}
}
onPressButton() {
var resultData = this.state.data;
if(resultData.length > 0){
console.log("RESULTDATA", resultData);
this.props.navigator.showModal({
title: "Modal",
screen: "App.SearchResult",
passProps: {
result: resultData,
}
});
}
}
When I clicked the button, it fires me this error :
'Error calling RCTEventEmiter.receiveTouches'
The log "RESULTDATA" is something like that with one or several items :
RESULTDATA', { '0':
{ id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: 'Sincere#april.biz'
} }
Second one
export default class SearchTab extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dicoDataSource: ds.cloneWithRows(realm.objects('User')),
searchText:'',
data:[]
}
}
onPressButton() {
var resultData = this.state.data;
if(resultData.length > 0){
console.log("RESULTDATA", resultData);
this.props.navigator.showModal({
title: "Modal",
screen: "App.SearchResult",
passProps: {
result: resultData.name, <== HERE THE ONLY DIFFERENCE
}
});
}
}
With this code, the modal screen shows up but when I log this.props.result it shows undefined.
componentDidMount(){
console.log("PROPS", this.props.result);
}
I would like to use this data to make a ListView in the modal screen which works fine.
No idea what to do with that. I already tested separately some UI elements and with different combinations like described above.
And I want to have the first one to work.
Any suggestion would be highly appreciated.
EDIT
Nobody ?
EDIT 2
Here my SearchResult class:
import React, {Component} from 'react';
import {
TextInput,
View,
TouchableOpacity,
StyleSheet,
TouchableHighlight,
Text,
Button
} from 'react-native';
import realm from '../realmDB/realm';
import { ListView } from 'realm/react-native';
import {Navigation} from 'react-native-navigation';
import EStyleSheet from 'react-native-extended-stylesheet';
export default class SearchResult extends Component {
static navigatorStyle = {
leftButtons: [{
title: 'Close',
id: 'close'
}]
};
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
resultDataSource: ds.cloneWithRows(this.props.result),
searchText:'',
data:[]
}
}
renderRow(rowData, sectionId, rowId, highlightRow){
return(
<View style={styles.row}>
<Text style={styles.rowText}>{rowData.username}</Text>
</View>
)
}
render() {
return (
<View style={styles.container}>
<TextInput style = {styles.searchText}
placeholder="Type your research"
autoCorrect={true}
returnKeyLabel="search"
underlineColorAndroid="black"
placeholderTextColor="black"
value = {this.state.searchText}
onChange={this.setSearchText.bind(this)}
/>
<TouchableOpacity onPress = {() => this.onPressButton(this.state.searchText)}>
<Text style={styles.button}>SEARCH</Text>
</TouchableOpacity>
<ListView
navigator={this.props.navigator}
enableEmptySections={true}
dataSource={this.state.resultDataSource}
renderRow={this.renderRow.bind(this)}
renderSeparator={(sectionId, rowId) => <View key={rowId} style={styles.separator} />}
/>
</View>
);
I also open an issue here: https://github.com/wix/react-native-navigation/issues/1249
Make sure that you are passing the 'result' props from the 'App.SearchResult' to the 'SearchTab' component when you are rendering it in the screen component.
Ok, it was not a context losing problem. It was about the data structure I used. I had to make nested objects in order to pass the data.
I was trying to pass a wrong format/structure of data that react-native-navigation package did not allow. Only an object can be passed

How does the list property of realm work?

I can't make a list with realm in order to use it with a realm ListView.
I need to make 2 or 3 ListViews, you can see the pieces of code below:
realm.js:
const Realm = require ('realm');
class UserEntrySchema extends Realm.Object {}
UserEntrySchema.schema = {
name:'User',
primaryKey:'id',
properties:{
id:'int',
name:'string',
username: 'string',
email: 'string',
}
};
class UserListSchema extends Realm.Object {}
UserListSchema.schema = {
name:'UserList',
properties: {
users :{type:'list', objectType:'User'}
}
};
class HistorySchema extends Realm.Object {}
HistorySchema.schema = {
name : 'History',
properties :{
items : {type:'list',objectType:'User'}
}
};
export default new Realm({
schema:[UserEntrySchema,UserListSchema,HistorySchema], schemaVersion:0});
I make a first ListView with the following code:
export default class SearchTabScreen1 extends Component {
constructor(props) {
super(props);
this.state = {
searchText:'',
data:[]
};
}
componentDidMount(){
this.fetchUsers();
}
fetchUsers(){
console.log("FEEEEEETCH");
fetch('http://jsonplaceholder.typicode.com/users')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
data : responseJson
});
var data = this.state.data;
realm.write(() => {
for (var i = 0; i < data.length; i++){
let myUser = realm.create('User',data[i],true);
}
console.log("ALLUSER", realm.objects('User'));
});
})
.catch(function(e) { // Failure callback registartion
alert('Failure fetching data');
console.log(e)
});
}
I tried to make a list property using
UserListSchema
with no success.
And for now this ListView works fine even when I'm using
realm.objects('User')
as datasource.
I don't know if it's good to do it like that or not.
The second ListView is a "search history", when a row of the first ListView is clicked, it called the following method that pushes another screen (I am using react-native-navigation package) and populate a realm list. I would like to use this list as datasource for the 'history ListView".
onPushPress(rowData) {
this.props.navigator.showModal({
title: "Random Title",
screen: "Project.WordDefinition",
passProps: {
definition: rowData.name
}
});
realm.write(() => {
let historyList = realm.create('History',{},true);
historyList.items.push({rowData});
});
}
}
I got this error:
'Property' must be of type number
I also tried:
onPushPress(rowData) {
console.log("ROWDATA", rowData);
this.props.navigator.showModal({
title: "Titre",
screen: "AccessiDico.WordDefinition",
passProps: {
definition: rowData.name
}
});
realm.write(() => {
let historyList = realm.create('History',{},true);
historyList.items.push({
id:rowData.id,
name:rowData.name,
username: rowData.username,
email: rowData.email,
});
console.log("ROWDATA",rowData);
console.log("ITEMS",realm.objects('History'));
console.log("List",historyList.items);
});
}
}
And I got this error:
Attempting to create an object of type 'User' with an existing primary
key value
Does it means I can't use "my users" in the 'UserEntrySchema' to push them within a realm list ?
I would really appreciate some help, it has been a week that I am hard stuck with this :+1:
Thanks !
PS: Here how the history ListView is coded:
export default class HistoryTabScreen2 extends Component {
constructor(props) {
super(props);
// if you want to listen on navigator events, set this up
//this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
postDataSource: ds.cloneWithRows(realm.objects('History')),
};
}
renderRow(rowData, sectionId, rowId, highlightRow){
return(
<TouchableHighlight onPress={this.onPushPress.bind(this)}>
<View style={styles.row}>
<Text style={styles.rowText}>{rowData.name}</Text>
</View>
</TouchableHighlight>
)
}
render(){
return(
<ListView
dataSource={this.state.postDataSource}
renderRow={this.renderRow.bind(this)}
/>
);
}
And the log of my rowData when I clicked a row of the ListView:
'ROWDATA', { id: 5,
name: 'Chelsey Dietrich',
username: 'Kamren',
email: 'Lucio_Hettinger#annie.ca',
address:
{ street: 'Skiles Walks',
suite: 'Suite 351',
city: 'Roscoeview',
zipcode: '33263',
geo: { lat: '-31.8129', lng: '62.5342' } },
phone: '(254)954-1289',
website: 'demarco.info',
company:
{ name: 'Keebler LLC',
catchPhrase: 'User-centric fault-tolerant solution',
bs: 'revolutionize end-to-end systems' } }
I just responded to a question about list objects.
take a look at this link, and then ask for further clarification if you need it. At the end of the post I provided a working example of creating/modifying/appending/deleting objects from a realm List object.
How can I properly copy objects from one Realm object to another object
To create a list is pretty straightforward, here's the simplest case:
class Letters: Object {
var letterList = List<Letter>()
}
So to create a list, you need to know the Object subclass you will be using. (Letter in the above example).
To add to the list, you create an object (item - below), and then append to the list:
firstList.letterList.append(item)

TypeError: Requested keys of a value that is not an object. React-native

guys! I first making app with and have some problem with response values! When i click GO, i sent request and get response from it. Im looking in the console, i have 20 items from response on 'london' locate, so it works, but doesnt parse my json to key-valuse! Help me, please, guys!
Using latest React-native + android virtual emulator 7.1.1
Here is my code from SearchPage.js
function urlForQueryAndPage(key, value, pageNumber) {
var data = {
country: 'uk',
pretty: '1',
encoding: 'json',
listing_type: 'buy',
action: 'search_listings',
page: pageNumber
};
data[key] = value;
var querystring = Object.keys(data)
.map(key => key + '=' + encodeURIComponent(data[key]))
.join('&');
return 'http://api.nestoria.co.uk/api?' + querystring;
};
export default class SearchPage extends Component {
constructor(props) {
super(props);
this.state = {
searchString: 'london',
isLoading: false,
message: ''
};
}
onSearchTextChanged(event) {
this.setState({ searchString: event.nativeEvent.text });
}
onSearchPressed() {
var query = urlForQueryAndPage('place_name', this.state.searchString, 1);
this._executeQuery(query);
}
_executeQuery(query) {
this.setState({ isLoading: true });
console.log(query);
fetch(query)
.then(response => response.json())
.then(json => this._handleResponse(json.response))
.catch(error =>
this.setState({
isLoading: false,
message: 'Something bad happened ' + error
}));
}
_handleResponse(response) {
this.setState({ isLoading: false , message: '' });
if (response.application_response_code.substr(0, 1) === '1') {
console.log('Properties found: ' + response.listings.length);
this.props.navigator.push({
id: 'SearchResults',
name: 'SearchResults',
passProps: {listings: response.listings}
});
console.log(passProps);
} else {
this.setState({ message: 'Location not recognized; please try again.'});
}
}
And here is my code from SearchResults.js
export default class SearchResults extends Component {
constructor(props) {
super(props);
var dataSource = new ListView.DataSource(
{rowHasChanged: (r1, r2) => r1.lister_url !== r2.lister_url});
this.state = {
dataSource: dataSource.cloneWithRows(this.props.listings)
};
}
renderRow(rowData, sectionID, rowID) {
return (
<TouchableHighlight
underlayColor='#dddddd'>
<View>
<Text>{rowData.title}</Text>
</View>
</TouchableHighlight>
);
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}/>
);
}
}
Look at the error text ( in red pointer)
End here it is response from console. Look at the items count!So response works!
Two things:
1-Try to put the .then right after response.json() like so:
fetch(query)
.then((response) => {
response.json()
.then(json => this._handleResponse(json.response))})
.catch(error =>
Update: Actually, changing the order of the .then is not necessary, it should work either way.
2-I believe that when you console.log(passProps), passProps is not defined properly, therefore, console.log(passProps) won't print anything (Correct me if I am wrong). You can try this:
var passProps = {listings: response.listings};
this.props.navigator.push({
id: 'SearchResults',
name: 'SearchResults',
passProps: passProps
});
console.log(passProps);
I see that you are using this.props.listings inside your SearchResults component after passing listings as props using the navigator. The only way for you to be able to do this.props.listings directly (instead of this.props.passProps.listings) is if you have something like this in your renderScene method of your navigator:
if (routeId === 'SearchResults') {
return (<SearchResults {...route.passProps} navigator={navigator} />);
}
or
if (route.id === 'SearchResults') {
return (<SearchResults listings={route.passProps.listings} navigator={navigator} />);
}
To make sure you are passing the props correctly to the SearchResults component, do a console.log in your render method of SearchResults
render() {
console.log("SearchResults props: ", this.props);
return (
<ListView
I believe that if you get the fetch output right (as an object), the problem could be the way you wrote your ListView and/or dataSource.
Other than that, there is not enough information (Such as the expected json response, and what you actually got) to tell where the problem lies.
Cheers

React Native fetch from db-models

I am trying to fetch from db-models to ListView. Here is my code:
export default class todoDB extends Component {
constructor(props) {
super(props);
this.state = {
dataSource : new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
};
}
componentDidMount () {
this.fetchData();
}
fetchData () {
DB.users.get_all(function(result) {
let data = [];
for(let i = 1; i <= result.totalrows; i++) {
data.push(result.rows[i]);
}
this.setState({
dataSource: dataSource.cloneWithRows(data),
})
});
}
render () {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderList}
/>
);
}
renderList (item) {
return (
<View>
<Text>{item.age}</Text>
</View>
);
}};
After running I don`t have error or any output, only empty screen.
I using
"react": "15.4.2",
"react-native": "0.40.0"
"react-native-db-models": "^0.1.3"
I have not tested it but you could try this :
fetchData() {
DB.users.get_all((result) => {
let data = [];
for (let i = 1; i <= result.totalrows; i++) {
data.push(result.rows[i]);
}
this.setState((prevState) => (
{
dataSource: prevState.dataSource.cloneWithRows(data)
}));
});
}
Changes are : using arrow function instead of function(result) to keep the scope of this and updating the previous state prevState.dataSource.cloneWithRows(data) (in your code dataSource was undefined here)
As to why use prevState, it is to keep immutability. Little bit more info here : https://facebook.github.io/react/docs/react-component.html#setstate

Categories

Resources