I have an object, as you can see in picture, when i console.log() it, in first row it says course is an array of 0 length. when i expand it, it says length is 1, when i do course.length it says 0. Object.keys(course).length also says 0.
What i do in my app is, I have a listview. each item on listview is expandable. each item is a container, and each container have courses. i got containers and courses from remote server. everything was working perfectly. now i'm trying to load data from local database. it's not working anymore...
Please see my simplified code :
export default class Main extends Component{
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
})
};
}
componentWillMount(){
this.fetchData();
}
fetchData(){
let data = fetch..... //// fetches data
let dsource = {};
for(let i=0; i < data.containers.length; i++){
let container = data.containers[i];
dsource[i] = {
containerId: containder.id,
course: [],
}
for(let x=0; x < container.courses.length; x++){
let course = container.courses[x];
dsource[i].course.push({
courseId: course.id,
courseName: course,name
});
}
}
this.setState({
dataSource: this.state.dataSource.cloneWithRows(dsource)
});
}
I read lots of questions on stackoverflow, many articles, but no successs :( Object.keys(Obj).length Obj.length all returns 0. Some says because Obj.length will only show enumerable properties. i tried adding enumerable properties to object with Object.defineproperty but no changes.
any solutions? any help is highly appreciated.
The whole code (react native) :
"use strict";
import React, {Component, PropTypes} from 'react';
import {
ActivityIndicator,
ListView,
StyleSheet,
Text,
View,
Image,
NetInfo,
AlertIOS,
TouchableOpacity,
ScrollView,
Dimensions,
} from 'react-native';
let SQLite = require('react-native-sqlite-storage');
let Loading = require("./Loading");
let Accordion = require('react-native-accordion');
let DeviceInfo = require('react-native-device-info');
import Icon from 'react-native-vector-icons/Ionicons';
import { Actions } from 'react-native-router-flux';
import I18n from 'react-native-i18n';
import translations from './translations';
I18n.fallbacks = true;
let LOADING = {};
import CodePush from "react-native-code-push";
let { width, height } = Dimensions.get('window');
let db = SQLite.openDatabase({name : "oc.db", location: 'default'});
export default class Courses extends Component {
constructor(props) {
super(props);
this.state = {
isLoading: false,
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
isConnected: true,
dataLoaded: 0,
restartAllowed: true
};
}
toggleAllowRestart() {
this.state.restartAllowed
? CodePush.disallowRestart()
: CodePush.allowRestart();
this.setState({ restartAllowed: !this.state.restartAllowed });
}
sync() {
CodePush.sync(
{
installMode: CodePush.InstallMode.IMMEDIATE,
updateDialog: false
},
);
}
componentWillMount() {
NetInfo.isConnected.fetch().then(isConnected => {
this.setState({
isConnected: isConnected
});
});
NetInfo.isConnected.addEventListener(
'change',
isConnected => {
this.setState({
isConnected: isConnected
});
}
);
this.fetchData();
this.sync();
}
componentWillReceiveProps() {
this.fetchData();
this.setState({
keyForCourse: Date()
});
if(this.props.goto == 'register'){
Actions.register({type: 'reset'});
}
}
fetchData() {
console.log('Courses: fetchData running');
if(this.state.isConnected == 'wifi' || this.state.isConnected == 'cell' || this.state.isConnected == 'true' || this.state.isConnected){
this.setState({
isLoading: true,
});
db.transaction((tx) => {
tx.executeSql("SELECT * FROM users WHERE active=?",['yes'], (tx, results) => {
let len = results.rows.length;
let row = results.rows.item(0);
let userName = row.userName;
let userMail = row.userMail;
let userId = row.userId;
///// Getting courses list
db.transaction((tx) => {
tx.executeSql("SELECT * FROM containersC WHERE userId=?",[userId], (tx, results) => {
let dsource = {};
let len = results.rows.length;
if(len > 0){
for(let ind = 0; ind < len; ind++ ){
let cntr = results.rows.item(ind);
dsource[ind] = {
nid: cntr.nid,
title: cntr.title,
course: [],
courses: {},
};
//// Get courses for each container
db.transaction((tx) => {
tx.executeSql("SELECT * FROM courses WHERE userId=? AND container_nid=?",[userId, cntr.nid], (tx, results) => {
let lenc = results.rows.length;
if(lenc > 0){
for(var j=0; j < lenc; j++){
let crs = results.rows.item(j);
console.log('Course:', crs);
dsource[ind].course.push({
course_id: crs.course_id,
title: crs.title,
cost: crs.cost,
status: crs.status,
period: crs.period // .time_sys
});
dsource[ind].courses[j] = {
course_id: crs.course_id,
title: crs.title,
cost: crs.cost,
status: crs.status,
period: crs.period // .time_sys
};
}
dsource[ind].total = lenc;
}
}, function(){
console.log('Courses: Something went wrong Line 142');
});
});
//// End getting courses for containers
}
this.setState({
dataSource: this.state.dataSource.cloneWithRows(dsource),
isLoading: false,
dataLoaded: len
});
}
}, (err)=>{
console.log('Courses: Something went wrong', err);
});
}
);
//// End getting courses list
}, function(){
console.log('Courses: Unable to select users from database');
});
});
} else {
AlertIOS.alert(
I18n.t("no_connection_title"),
I18n.t("no_connection_desc")
);
}
}
selectRow(d, n) {
Actions.cdetails({cid: d, tit: n});
//Actions.rdetails({cid: d, tit: n});
}
renderRow(data) {
let header = (
<View style={{ backgroundColor: '#fff', margin: 7, marginBottom: 0 }}>
<View style={styles.rowContainer}>
<View style={styles.textContainer}>
<Icon name="ios-arrow-up" color="#00a2dd" size={30}></Icon>
<Text style={styles.title}>{data.title}</Text>
</View>
</View>
</View>
);
let headerOpen = (
<View style={{ backgroundColor: '#fff', margin: 7, marginBottom: 0 }}>
<View style={styles.rowContainer}>
<View style={styles.textContainer}>
<Icon name="ios-arrow-down" color="#00a2dd" size={30}></Icon>
<Text style={styles.title}>{data.title}</Text>
</View>
</View>
<View style={styles.separator}></View>
</View>
);
///////////
let cid = [];
let content = [];
let cll = data.total;
console.log('Data to render :', data);
console.log('Courses to render :', data.course);
for(let x=0; x < cll; x++){
cid[x] = data.course[x].course_id;
let courseCost;
switch(data.course[x].cost){
case 0:
courseCost = I18n.t("course_fee_free");
break;
case 1:
courseCost = data.course[x].cost;
break;
}
content.push(
<TouchableOpacity key={cid[x]} onPress={()=>{this.selectRow(data.course[x].course_id, data.course[x].title)}} >
<View style={[styles.cardContainer, {marginBottom: 5}, x == 0 ? { paddingTop: 6, } : {}, x == (cll+1) ? { marginBottom: 3} : {}]} key={cid[x]} >
<View style={styles.card}>
<View resizeMode="cover" style={styles.cardTitleContainer}>
<Text style={styles.cardTitle}>{data.course[x].title}</Text>
</View>
<View
style={{
padding : 15,
}}
>
<Text style={styles.cardContent}>
<Icon name="ios-calendar" color="#00a2dd" size={10}> {data.course[x].period}</Icon>{'\n'}
<Icon name="ios-pricetag" color="#00a2dd" size={10}> {courseCost}</Icon>
</Text>
</View>
</View>
</View>
</TouchableOpacity>
);
}
let clist = (
<ScrollView style={styles.scrollView}>
<View style={{
padding: 6,
paddingBottom: 0,
borderTopColor: '#fff',
backgroundColor: '#fff',
margin: 7,
marginTop: 0,
}}>{content}</View>
</ScrollView>
);
////////////
return (
<Accordion
header={header}
headerOpen={headerOpen}
content={clist}
easing="easeOutCubic"
underlayColor="#ebebeb"
/>
);
}
render() {
let content= null;
if(this.state.isLoading){
content = <Loading/>;
} else {
if(this.state.dataLoaded < 1){
content = <View style={styles.errorContainer}>
<View style={styles.error}>
<Text style={styles.Errortext}>
{I18n.t("courses_no_course_available")}
</Text>
</View>
</View>;
} else {
content = <View style={{
flex: 1
}}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow.bind(this)}
/>
</View>;
}
}
return (
<View style={styles.container}>
{content}
</View>
);
}
}
let styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "white",
flexDirection: "column",
justifyContent: "center",
backgroundColor: '#e4e7ea',
},
separator: {
height: 1,
backgroundColor: "#d0d1d3",
},
scrollSpinner: {
marginVertical: 20,
},
cardContainer:{
flex: 1,
alignItems: 'stretch',
paddingLeft: 6,
paddingRight: 6,
borderColor: '#d0d1d3',
borderWidth: 1,
borderRadius: 5
},
card:{
flex: 1,
backgroundColor: '#ffffff',
borderRadius: 2,
borderColor: '#ffffff',
borderWidth: 1,
/*shadowColor: 'rgba(0, 0, 0, 0.12)',
shadowOpacity: 0.8,
shadowRadius: 2,
shadowOffset: {
height: 1,
width: 2,
},
*/
},
cardTitleContainer:{
flex: 1,
height: 35,
},
cardTitle:{
position: 'absolute',
top: 5,
left: 5,
backgroundColor: 'transparent',
padding: 10,
fontSize: 12,
color: '#4c4b4b',
fontWeight: 'bold',
},
rowContainer: {
flexDirection: 'column',
padding: 5,
},
textContainer: {
flexDirection: 'row',
flex: 1,
padding: 5
},
title: {
paddingTop: 7,
paddingLeft: 5,
color: '#00a2dd'
},
errorContainer: {
flex: 1,
flexDirection: "column",
backgroundColor: '#e4e7ea',
alignItems: 'center',
},
error: {
marginTop: 75,
width: width -150,
height: 100,
borderRadius: 15,
backgroundColor: '#ecebeb',
alignItems: 'center',
justifyContent: 'center',
},
Errortext: {
color: '#757575'
},
});
Courses = CodePush(Courses);
Object.keys() returns an array whose elements are strings corresponding to the enumerable properties found directly upon object . The ordering of the properties is the same as that given by looping over the properties of the object manually.
Checking empty object with JavaScript It will return false and not throw a TypeError .
There are only seven values that are falsy in JavaScript, and empty objects are not one of them. An empty object is an object that has no properties of its own. You can use the Object. keys() function to check if an object is empty as shown below.
Use Object. keys will return an array, which contains the property names of the object. If the length of the array is 0 , then we know that the object is empty. We can also check this using Object. values and Object.
Try this,
const keys =[];
const person = {
name : 'Jobelle',
age :22,
mob :8547391599
}
Object.getOwnPropertyNames(tempObj).forEach(prop => {
keys.push(prop);
});
There are 3 factors that can cause the general behavior you describe. In your case, I think it's the first:
When you invoke console.log(x)
, the Chrome console will show a summary of the object x
at the time. However, when you expand the object, the value is obtained again. The detailed object you see may have changed since the call to console.log()
, and changes will appear in the detail.
Properties may belong to an object's prototype (as opposed to "own" properties):
> x = {a:1}
{ a: 1 }
> y = Object.create(x)
> y.a
1
> y
{}
> Object.keys(y)
[]
Properties may be non-enumerable, and won't show up in key listings. length
is a non-enumerable property.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With