I want to develop a React Native app, and I want to have locally stored some data of the format:
[
{
"id": 1,
"text": "Lorem ipsum",
"viewed": false
},
{
"id": 2,
"text": "Second lorem",
"viewed": false
},
{
"id": 3,
"text": "Last lorem",
"viewed": false
}
]
I want this data to be available when the user first downloads the app. Then based on the user's navigation, the corresponding data in the db will change the viewed flag to true. This has to be persistent when the app will be updated by the user on the next version.
Any tips/ideas on how to achieve this?
Currently I'm looking into Realm.io but I'm not sure if this is the right tool for me.
You can use AsyncStorage for that like so:
const data = [
{
"id": 1,
"text": "Lorem ipsum",
"viewed": false
},
{
"id": 2,
"text": "Second lorem",
"viewed": false
},
{
"id": 3,
"text": "Last lorem",
"viewed": false
}
]
try {
await AsyncStorage.setItem(
'SOME_KEY', JSON.stringify(data)
);
} catch (error) {
// Handle error
}
Later on if you want to fetch/change you can do:
AsyncStorage.getItem('SOME_KEY', (err, result) => {
console.log(JOSN.parse(result));
});
If data is more than pouchDb is suggested option.
You can install it with
npm install pouchdb-react-native --save
Simple Demo
import PouchDB from 'pouchdb-react-native'
const db = new PouchDB('mydb')
// use PouchDB
db.get('4711')
.then(doc => console.log(doc))
Advance Demo
'use strict'
import React from 'react'
import {
AsyncStorage,
ListView,
Navigator,
StyleSheet,
Text,
TextInput,
TouchableHighlight,
View
} from 'react-native'
import ActionButton from 'react-native-action-button'
import PouchDB from 'pouchdb-react-native'
const localDB = new PouchDB('myDB')
console.log(localDB.adapter)
AsyncStorage.getAllKeys()
.then(keys => AsyncStorage.multiGet(keys))
.then(items => console.log('all pure Items', items))
.catch(error => console.warn('error get all Items', error))
export default React.createClass({
getInitialState () {
const updateDocs = () => {
localDB.allDocs({include_docs: true, limit: null})
.then(result => {
const items = result.rows.map(row => row.doc)
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1.id !== r2.id})
this.setState({
dataSource: ds.cloneWithRows(items),
count: items.length
})
})
.catch(error => console.warn('Could not load Documents', error, error.message))
}
localDB.changes({since: 'now', live: true})
.on('change', () => updateDocs())
updateDocs()
return {
dataSource: null,
syncUrl: 'http://localhost:5984/test'
}
},
render () {
const renderScene = (route, navigator) => (
<View style={{flex: 1, marginTop: 20, backgroundColor: '#FFFFFF'}}>
{route.render()}
</View>
)
const renderMain = () => {
const insertAttachment = () => {
const doc = {
'title': 'with attachment',
'_attachments': {
'att.txt': {
'content_type': 'text/plain',
'data': 'TGVnZW5kYXJ5IGhlYXJ0cywgdGVhciB1cyBhbGwgYXBhcnQKTWFrZS' +
'BvdXIgZW1vdGlvbnMgYmxlZWQsIGNyeWluZyBvdXQgaW4gbmVlZA=='
}
}
}
localDB.post(doc)
.then(result => console.log('save.attachment', result))
.catch(error => console.warn('save.attachment.error', error, error.message, error.stack))
}
const insertRecords = count => {
for (let index = 0; index < count; index++) {
localDB.post({
text: `Record ${index}/${count}`
})
}
}
const destroy = count => {
localDB.destroy()
.then(() => console.log('destroyed'))
.catch(error => console.warn('destroyed', error))
}
const { dataSource } = this.state
const renderSeparator = (sectionID, rowID) => (
<View
key={rowID}
style={{borderColor: '#969A99', borderBottomWidth: StyleSheet.hairlineWidth}} />
)
const renderRow = (row) => {
const updateItem = () => {
const newRow = {...row}
newRow.clickCount = newRow.clickCount ? newRow.clickCount + 1 : 1
localDB.put(newRow)
.then(result => console.log('Updated Item', result))
.catch(error => console.warn('Error during update Item', error))
}
return (
<TouchableHighlight onPress={updateItem}>
<View key={row._id}>
<Text style={{fontWeight: 'bold'}}>{row._id}</Text>
<Text>{JSON.stringify(row, null, 4)}</Text>
</View>
</TouchableHighlight>
)
}
const renderList = () => (
<ListView
dataSource={dataSource}
renderRow={renderRow}
renderSeparator={renderSeparator}
enableEmptySections />
)
return (
<View style={{flex: 1}}>
<View>
{!!this._sync && <Text style={{fontWeight: 'bold'}}>{this.state.syncUrl}</Text>}
<Text style={{fontWeight: 'bold'}}>Count: {this.state.count}</Text>
</View>
<View
style={{borderColor: '#969A99', borderBottomWidth: StyleSheet.hairlineWidth}} />
{!dataSource
? (<Text>Loading...</Text>)
: renderList()
}
<ActionButton buttonColor='#78B55E'>
<ActionButton.Item
buttonColor='#005BFF'
title='Destroy Database'
onPress={destroy}>
<Text>destroy</Text>
</ActionButton.Item>
<ActionButton.Item
buttonColor='#005BFF'
title='Insert Attachments'
onPress={insertAttachment}>
<Text>attach</Text>
</ActionButton.Item>
<ActionButton.Item
buttonColor='#005BFF'
title='Insert 250 Records'
onPress={() => insertRecords(250)}>
<Text>insert</Text>
</ActionButton.Item>
<ActionButton.Item
buttonColor='#005BFF'
title='Sync'
onPress={() => this._navigator.push({name: 'Sync', render: renderSync})}>
<Text>sync</Text>
</ActionButton.Item>
<ActionButton.Item
buttonColor='#005BFF'
title='Add Item'
onPress={() => this._navigator.push({name: 'AddItem', render: renderAddItem})}>
<Text>+</Text>
</ActionButton.Item>
</ActionButton>
</View>
)
}
const renderButton = (text, onPress) => {
return (
<TouchableHighlight
onPress={onPress}
style={{
flexDirection: 'column',
paddingTop: 3,
paddingBottom: 3,
marginLeft: 10,
marginRight: 10,
backgroundColor: '#78B55E',
borderRadius: 5
}}>
<Text
style={{
flex: 1,
fontSize: 18,
fontWeight: 'bold',
color: '#FFFFFF',
paddingLeft: 10,
paddingRight: 10,
paddingTop: 2,
alignSelf: 'center'
}}>
{text}
</Text>
</TouchableHighlight>
)
}
const renderSync = () => {
const addSync = () => {
if (this._sync) {
this._sync.cancel()
this._sync = null
}
if (this.state.syncUrl) {
const remoteDb = new PouchDB(this.state.syncUrl, {ajax: {cache: false}})
this._sync = PouchDB.sync(localDB, remoteDb, {live: true, retry: true})
.on('error', error => console.error('Sync Error', error))
.on('change', info => console.log('Sync change', info))
.on('paused', info => console.log('Sync paused', info))
}
this._navigator.pop()
}
return (
<View style={{flex: 1}}>
<TextInput
style={{
height: 40,
lineHeight: 40,
fontSize: 16,
paddingLeft: 10,
paddingRight: 10
}}
autoFocus
keyboardType='url'
clearButtonMode='always'
placeholder='enter URL'
onChangeText={(text) => this.setState({syncUrl: text})}
value={this.state.syncUrl} />
{renderButton('Add Sync', addSync)}
</View>
)
}
const renderAddItem = () => {
const addItem = () => {
localDB.post(JSON.parse(this.state.newItem))
.then(result => {
this.setState({newItem: ''})
this._navigator.pop()
})
.catch(error => console.error('Error during create Item', error, error.message))
}
return (
<View style={{flex: 1}}>
<TextInput
style={{
height: 340,
lineHeight: 40,
fontSize: 16,
paddingLeft: 10,
paddingRight: 10
}}
autoFocus
clearButtonMode='always'
multiline
placeholder='JSON Object here'
onChangeText={(text) => this.setState({newItem: text})}
value={this.state.newItem} />
{renderButton('Add Item', addItem)}
</View>
)
}
return (
<View style={{flex: 1}}>
<Navigator
ref={navigator => { this._navigator = navigator }}
renderScene={renderScene}
initialRoute={{name: 'Main', render: renderMain}}
/>
</View>
)
}
})
Related
I'm working on flatlist with checkbox but could not select multiple checkboxes inside flatlist. Every time only single item is selected. Wanted to add dynamic checkbox according to the list and have to handle all checkbox using one function. I have used the following code but its not working. Any help would be appreciated.
import React, { useState, useEffect } from 'react';
import {
SafeAreaView,
StyleSheet,
Text,
View,
FlatList,
TouchableOpacity,
Image,
ActivityIndicator,
} from 'react-native';
import CheckBox from '#react-native-community/checkbox';
const App = () => {
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState([]);
useEffect(() => {
getListPhotos();
return () => {
}
}, [])
getListPhotos = () => {
const apiUrl = 'https://jsonplaceholder.typicode.com/photos';
fetch(apiUrl)
.then((res) => res.json())
.then((resJson) => {
setData(resJson);
}).catch((err) => { console.error('Error', err); })
.finally(() => setIsLoading(false))
}
onChangeValue = (item, index) => {
const newData = data.map(newItem => {
if (newItem.id == item.id) {
return {
...newItem,
selected: true,
}
}
return {
...newItem,
selected: false,
}
})
setData(newData);
}
renderItem = ({ item, index }) => {
return (
<View style={styles.item}>
<Image style={styles.image}
source={{ uri: item.url }}
resizeMode='contain'
/>
<View style={styles.wrapText}>
<Text >{item.title}</Text>
<CheckBox
value={item.selected}
style={styles.ckItem}
disabled={false}
onAnimationType='fill'
offAnimationType='fade'
boxType='square'
onValueChange={() => onChangeValue(item, index)}
/>
</View>
</View>
)
}
return (
<SafeAreaView style={styles.container}>
{isLoading ? <ActivityIndicator /> : (<FlatList
style={styles.list}
data={data}
renderItem={renderItem}
//keyExtractor={(item, index) => item.id}
keyExtractor={item => `key-${item.id}`}
/>)}
<View>
<Text style={styles.wrapButton}></Text>
<TouchableOpacity style={styles.button}>
<Text>
Show item you selected
</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
list: {
flex: 1,
padding: 8,
},
wrapButton: {
width: '100%',
justifyContent: 'center',
alignItems: 'center',
},
button: {
padding: 16,
backgroundColor: 'orange',
// justifyContent:'center',
// alignItems:'center',
alignSelf: 'center',
width: '50%'
},
item: {
marginTop: 8,
flexDirection: 'row',
padding: 4,
shadowColor: '#000',
shadowOffset: {
width: 0, height: 2
},
shadowOpacity: 0.25,
shadowRadius: 4,
elevation: 5,
},
image: {
width: 100,
height: 150,
},
wrapText: {
flex: 1,
marginTop: 16,
marginLeft: 8,
},
ckItem: {
width: 20,
height: 20,
marginTop: 5,
},
});
export default App;
onValueChange={newValue => onChangeValue(item, index, newValue)}
onChangeValue = (item, index, newValue) => {
const newData = data.map(newItem => {
if (newItem.id == item.id) {
return {
...newItem,
selected: newValue,
}
}
return newItem
})
setData(newData);
}
You can achieve by using below plugins
https://bestofreactjs.com/repo/tableflip-react-native-select-multiple-react-react-native-awesome-components
https://github.com/vakiller/react-native-flatlist-multiple-choose/blob/master/readme.md
I want to have a loading spinner appear in the middle of the screen while the file is being uploaded.
The clicked file is loaded and appears in the file list as well.
I imported ActivityIndicator from 'react-native'.
When I wrote the code after as a test, the loading spinner was well seen.
However, I wanted to make the spinner appear only the file is loaded. So, I wrote the code, but the loading spinner does not appear.
import {Text,View,ImageBackground,Image,StyleSheet,TouchableOpacity,FlatList,Button,ActivityIndicator} from 'react-native';
export default function FileUpload({route, navigation}) {
const [multipleFile, setMF] = useState([])
const [isLoading, setLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 5000);
}, [])
const addEntry = (data) => {
let newObj = {
"id": randId(),
"name" : data.filename,
"text" : data.text,
}
console.log('Finish load');
setMF([...multipleFile, newObj]);
console.log(multipleFile)
};
const randId = () => {
let id = ''
for (var i = 0; i < 10; i++) {
id += String.fromCharCode(Math.trunc(Math.random()*85) + 48)
}
return id
}
const sendFile = () => {
axios({
method: 'post',
url: '',
data: {
"uri": ""
}
}).then((res) =>{
addEntry(res.data)
}
).catch((err) => console.log(err));
}
const renderItem = ({ item }) => (
<Text>{item.name}</Text>
);
return (
<ImageBackground source={require('../images/bg2.png')}
style={{width: '100%', height: '100%'}}>
<View>
<TouchableOpacity onPress={() => {
DocumentPicker.getDocumentAsync().then((res) => {
console.log(res)
if (res.type == 'success') {
console.log('load start');
if(isLoading){
return(
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<ActivityIndicator size="large"/>
</View>
);
}
sendFile()
} else {
console.log('you cancelled')
}
})
}}
style={{alignItems: 'center'}}>
<Image source ={require('../images/cloud.png')}
style={styles.image}
/>
<View style={styles.viewTextStyle}>
<Text style={styles.textStyle}>{'Upload Files'} </Text>
<Text style={{fontSize:60, color:'white'}}> + </Text>
<Text style={styles.textStyle1}>{'Browse and select your file \n you want to upload'}</Text>
</View>
</TouchableOpacity>
</View>
<View style={styles.listHeader}>
<Text style={{textAlign: 'center', fontSize: 18}}> File List </Text>
</View>
<FlatList
style={styles.scrollContainer}
data={multipleFile}
renderItem={renderItem}
keyExtractor={item => item.id.toString()}>
</FlatList>
{/* <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<ActivityIndicator size="large"/>
</View> */}
<TouchableOpacity onPress={() => {
// console.log(multipleFile[0].name)
navigation.navigate('Details Search',
multipleFile[0]
)}}>
<View style={styles.button}>
<Text style={styles.buttonText}>Next</Text>
</View>
</TouchableOpacity>
</ImageBackground>
);
}
set the default state to false
const [isLoading, setLoading] = useState(false);
remove this effect
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 5000);
}, [])
remove loading view from DocumentPicker.getDocumentAsync()
if (res.type == 'success') {
sendFile()
} else {
console.log('you cancelled')
}
set loading true/false in sendFile()
const sendFile = () => {
setLoading(true);
axios({
method: 'post',
url: '',
data: {
"uri": ""
}
}).then((res) =>{
setLoading(false)
addEntry(res.data)
}
).catch((err) => setLoading(false));
}
const renderItem = ({ item }) => (
<Text>{item.name}</Text>
);
add loading view in main return
return (
....
if(isLoading){
return(
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<ActivityIndicator size="large"/>
</View>
);
}
....
)
I want to get specific the first two elements from a webservice and print it to a console it is returning me 1000 items. Can anyone guide me on how I can print only the first two elements
import React from "react";
import {StyleSheet,View,ActivityIndicator,FlatList,Text,TouchableOpacity} from "react-native";
export default class Source extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: "Source Listing",
headerStyle: {backgroundColor: "#fff"},
headerTitleStyle: {textAlign: "center",flex: 1}
};
};
constructor(props) {
super(props);
this.state = {
loading: false,
items:[]
};
}
FlatListItemSeparator = () => {
return (
<View style={{
height: .5,
width:"100%",
backgroundColor:"rgba(0,0,0,0.5)",
}}
/>
);
}
renderItem=(data)=>
<TouchableOpacity style={styles.list}>
<Text style={styles.lightText}>{data.item.name}</Text>
<Text style={styles.lightText}>{data.item.email}</Text>
<Text style={styles.lightText}>{data.item.company.name}</Text>
</TouchableOpacity>
render(){
{
if(this.state.loading){
return(
<View style={styles.loader}>
<ActivityIndicator size="large" color="#0c9"/>
</View>
)}}
return(
<View style={styles.container}>
<FlatList
data= {this.state.dataSource}
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem= {item=> this.renderItem(item)}
keyExtractor= {item=>item.id.toString()}
/>
</View>
)}
}
const parseString = require('react-native-xml2js').parseString;
fetch('http://192.168.200.133/apptak_service/apptak.asmx/Get_Item_Master')
.then(response => response.text())
.then((response) => {
parseString(response, function (err, result) {
console.log(response[0],response[1])
});
}).catch((err) => {
console.log('fetch', err)
})
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff"
},
loader:{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#fff"
},
list:{
paddingVertical: 4,
margin: 5,
backgroundColor: "#fff"
}
});
I want it to be print on the console then I will modify it later to display it on the app. I am struggling to get this done Please help
You are parsing the response as string. If you want to print the first two item in console, you can do it like this bellow:
fetch('http://192.168.200.133/apptak_service/apptak.asmx/Get_Item_Master')
.then((response) => {
console.log(response.data[0],response.data[1])
}).catch((err) => {
console.log('fetch', err)
})
Perhaps what you need is the result?
parseString(response, function (err, result) {
console.log(result) // not console.log(response)?
});
Using JavaScript
fetch("http://192.168.200.133/apptak_service/apptak.asmx/Get_Item_Master")
.then((r) => r.text())
.then((t) => (new window.DOMParser()).parseFromString(t, "text/xml"))
.then((d) => console.log(d))
.catch((e) => console.error(e));
I have an issue with React Native Redux where I am calling a Redux action from the onChangeText function from inside a TextField. Normally, an update like this would only cause the TextField itself to update, however the whole page is being re-rendered upon each call of the function.
Here is the code for the TextField. The method in question is this.props.updateURL(value)
<TextField label='Server'
value={this.props.profile.url}
labelFontSize={textFont(16)}
tintColor='#B3B2B6'
autoCapitalize="none"
autoCorrect={false}
returnKeyType={'next'}
blurOnSubmit={false}
autoFocus={!this.props.profile.edited}
style={styles.inputStyle}
selectionColor={CUSRSOR_COLOR}
editable={!this.props.profile.edited}
onChangeText={async value => {
this.props.updateURL(value)
}}
renderAccessory={()=>{
return(<TouchableOpacity onPress={this.handleScanPress} >
<Image source={ImgScan} style={{height: 25, width: 25, overflow:'visible', marginBottom:20, marginRight: 10}}/>
</TouchableOpacity>);
}}
>
</TextField>
This is for the Redux methods mapStateToProps and mapDispatchToProps:
const mapStateToProps = (state) => {
return {
profile : state.profileReducer,
deviceUid: state.GlobalReducer.deviceUid,
locationsList: state.LogsReducer.locationList,
errorList: state.ErrorsReducer.failedList,
watermarkText: state.GlobalReducer.watermarkText,
alertPresent: state.LogsReducer.alertPresent
}
};
const mapDispatchToProps = (dispatch) => {
return {
updateURL : (url) => dispatch(updateURL(url)),
updateUserName : (userName) => dispatch(updateUserName(userName)),
updatePassword : (password) => dispatch(updatePassword(password)),
updateDeviceName : (deviceName) => dispatch(updateDeviceName(deviceName)),
allFieldsEntered : (url,userName,password) => dispatch(allFieldsEntered(url,userName,password)),
loginDevice: (url,userName,password,deviceName,deviceId,navigation,existingUser) => dispatch(callLoginApi(url,userName,password,deviceName,deviceId,navigation,existingUser)),
updateFailureMessage: (message) => dispatch(updateFailureMessage(message)),
showLoader: () => dispatch(showLoader()),
hideLoader: () => dispatch(hideLoader()),
updateRegistrationSuccess: (value) => dispatch(updateRegistrationSuccess(value)),
checkForInternet: () => dispatch(checkConnectivity()),
getProfileDetails: async(isToken) => await dispatch(fetchProfileDetails(isToken)),
updateLocationSwitch: (value) => dispatch(updateLocationStatus(value)),
updateIsEdit: (value) => dispatch(updateIsEdit(value)),
storeRegistrationFlagInAsync: () => dispatch(storeRegistrationFlagInAsync()),
isDeviceConnected: (value) => dispatch(isDeviceConnected(value)),
requestLocationPermissions: () => dispatch(requestLocationPermissions()),
passwordChanged: (value) => dispatch(updateIsPasswordChanged(value)),
isEditPage: (value) => dispatch(isEditPage(value)),
getDeviceName: () => dispatch(getDeviceName()),
shouldEnableLocation: (value) => dispatch(shouldEnableLocation(value)),
fetchLocationList: () => dispatch(fetchLocations()),
syncRecords: (url,userName,password,locationList,deviceId,isFromError,shouldPresentErrorMsg) => dispatch(syncFailedRecords(url,userName,password,locationList,deviceId,isFromError,shouldPresentErrorMsg)),
fetchFailedRecords: (shouldShowLoader) => dispatch(fetchFailedRecords(shouldShowLoader)),
updateDeviceAction: (action,deviceId,url) => dispatch(performDeviceAction(action,deviceId,url)),
callLogoutApi: (userName,password) => dispatch(callLogoutApi(userName,password)),
syncDeviceActions: () => dispatch(syncDeviceActions()),
syncPendingUpdates: (url,userName,password,deviceId) => dispatch(syncPendingUpdates(url,userName,password,deviceId)),
fetchPendingLocationsList: () => dispatch(fetchPendingLocationsList()),
showPasswordChangeAlert: (alertFlag,navigation) => dispatch(handleUIForPasswordChange(alertFlag,navigation)),
}
}
export default connect(mapStateToProps,mapDispatchToProps)(Profile);
Here are the reducers:
const initialState = {
url: '',
userName : '',
password : '',
deviceName : '',
resourceCode : '',
isDeviceConnected : false,
allFieldsFilled: false,
token: '',
gpsTrackingInterval : 5,
apiPostingInterval : 30,
failureMessage : '',
registered : false,
edited: false,
editPage: false,
isConnected: true,
shouldEnableLocation: false,
resourceDesc: '',
adminEmail: '',
companyName: ''
}
const profileReducer = (state=initialState,action) => {
switch (action.type) {
case actionTypes.UPDATE_URL :
return {
...state,
url: action.payload
}
...
}
This is the Redux action:
export const updateURL = (url) => {
return {
type: actionTypes.UPDATE_URL,
payload: url
};
};
Any help would be much appreciated.
import React, { Component } from 'react';
import {
StyleSheet, Text, View, TextInput, TouchableOpacity, Image,
KeyboardAvoidingView, ScrollView, SafeAreaView, Linking
} from 'react-native';
import { COLOR_BLACK, COLOR_GRAY_9, COLOR_TRANSPARENT, COLOR_GRAY_4 } from '../../../constants/colors';
import ImgProntoLogo from '../../../assets/images/pronto-logo.png';
import ImgPasswordVisibleIcon from '../../../assets/images/visibility.png';
import ImgUrl from '../../../assets/images/url.png';
import ImgBarcode from '../../../assets/images/scan-barcode.png';
import ImgUsernameIcon from '../../../assets/images/username.png';
import ImgPasswordIcon from '../../../assets/images/password.png';
import ImgPasswordHide from '../../../assets/images/password-hide.png';
import GlobalStyleSheet from '../../../constants/styles';
import {
PASSWORD, USERNAME, URL_CONNECT
} from '../../../constants/strings';
import { StackActions, NavigationActions } from 'react-navigation';
import Sync from '../../../utils/Syncing';
import { AsyncStorage } from 'react-native';
export default class Configuration extends Component {
constructor(props) {
super(props)
this.handleOpenURL = this.handleOpenURL.bind(this);
this.handleScanPress = this.handleScanPress.bind(this);
}
async componentWillMount() {
this.props.clearConfiguration();
this.props.checkConnectivity();
Linking.addEventListener('url', this.handleOpenURL);
Sync.removeDataFromUserTable();
Sync.removeDataFromCompanyTable();
}
componentDidMount() {
console.log("COMPONENT MOUNTING");
Linking.getInitialURL().then((url) => {
if (url) {
url = url.substring(18);
this.props.updateURL(url);
}
}).catch(err => console.error('An error occurred', err))
}
componentWillReceiveProps(props) {
console.log("WILL RECEIVE")
}
handleOpenURL = (event) => {
this.props.updateURL(event.url.substring(18))
}
copyRights() {
var currentYear = new Date().getFullYear().toString();
return '© '.concat(currentYear).concat(' Pronto Software Limited.All Rights Reserved.');
}
// Connect the device to the pronto connect
async connectDevice() {
this.props.showLoader();
this.props.resetConnectPasswordVisibility();
await this.props.connectDevice(this.props.configuration.url,
this.props.configuration.username, this.props.configuration.password);
let isDeviceConnected = await AsyncStorage.getItem("isConnected");
if (isDeviceConnected === "true") {
const resetAction = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Register' })],
});
this.props.navigation.dispatch(resetAction);
}
this.props.hideLoader();
}
static navigationOptions = {
header: null
}
handleScanPress() {
const action = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Scanner' })],
});
this.props.navigation.push('Scanner');
}
render() {
return (
<SafeAreaView style={GlobalStyleSheet.container}>
<KeyboardAvoidingView style={GlobalStyleSheet.container} >
<View style={styles.headerLogoView}>
<Image source={ImgProntoLogo} style={styles.logo} />
</View>
<ScrollView keyboardShouldPersistTaps="handled" style={styles.scrollViewStyle}>
<View style={{ flex: 1, height: '100%' }}>
<View style={styles.viewContainer}>
<Text style={[GlobalStyleSheet.textHeading4, GlobalStyleSheet.marginTop10,
GlobalStyleSheet.marginBottom10]}>CONFIGURE DEVICE</Text>
<View style={[GlobalStyleSheet.textInputView, GlobalStyleSheet.marginBottom10]}>
<Image style={GlobalStyleSheet.iconInputBar} source={ImgUrl} />
<TextInput
underlineColorAndroid={COLOR_TRANSPARENT}
style={GlobalStyleSheet.textInput}
autoCapitalize='none'
placeholder={URL_CONNECT}
value={this.props.configuration.url}
onChangeText={(value) => { this.props.updateURL(value) }}
editable={!(this.props.configuration.isDeviceConnected)}
/>
<TouchableOpacity style={[GlobalStyleSheet.passwordTouchable]} onPress={this.handleScanPress}>
<Image style={[GlobalStyleSheet.passwordShowHideIcon]} source={ImgBarcode} />
</TouchableOpacity>
</View>
<View style={[GlobalStyleSheet.textInputView, GlobalStyleSheet.marginBottom10]}>
<Image style={GlobalStyleSheet.iconInputBar} source={ImgUsernameIcon} />
<View style={[GlobalStyleSheet.flexRow, { flex: 1 }]}>
<TextInput
placeholder={USERNAME}
underlineColorAndroid={COLOR_TRANSPARENT}
style={GlobalStyleSheet.textInput}
onChangeText={(value) => { this.props.updateUsername(value) }}
editable={!(this.props.configuration.isDeviceConnected)}
/>
</View>
</View>
<View style={[GlobalStyleSheet.textInputView, GlobalStyleSheet.marginBottom10]} >
<Image style={[GlobalStyleSheet.iconInputBar]} source={ImgPasswordIcon} />
<View style={[GlobalStyleSheet.flexRow, { flex: 1 }]}>
<TextInput
placeholder={PASSWORD}
underlineColorAndroid={COLOR_TRANSPARENT}
contextMenuHidden={true}
style={GlobalStyleSheet.textInput}
autoCapitalize='none'
onChangeText={(value) => { this.props.updatePassword(value) }}
editable={!(this.props.configuration.isDeviceConnected)}
secureTextEntry={!(this.props.configuration.passwordVisibility)} />
<TouchableOpacity style={[GlobalStyleSheet.passwordTouchable]}
onPress={() => {
if (!this.props.configuration.isDeviceConnected) {
this.props.togglePasswordVisibility(this.props.configuration.passwordVisibility)
}
}}>
{
this.props.configuration.passwordVisibility ?
(<Image style={[GlobalStyleSheet.passwordShowHideIcon]} source={ImgPasswordVisibleIcon} />) :
(<Image style={[GlobalStyleSheet.passwordShowHideIcon]} source={ImgPasswordHide} />)
}
</TouchableOpacity>
</View>
</View>
{
this.props.configuration.isDeviceConnected ?
(
<TouchableOpacity style={GlobalStyleSheet.touchableBarProcessed} disabled={true} >
<Text style={GlobalStyleSheet.textTouchableBarProcessed}>CONNECTED</Text>
</TouchableOpacity>
) :
(this.props.configuration.url != "" &&
this.props.configuration.username != "" && this.props.configuration.password != "" ?
(
<TouchableOpacity style={[GlobalStyleSheet.touchableBarEnabled]}
onPress={async () => { await this.connectDevice() }}>
<Text style={GlobalStyleSheet.textTouchableBarEnabled}>CONNECT</Text>
</TouchableOpacity>
) :
(
<TouchableOpacity style={[GlobalStyleSheet.touchableBarDisabled]} disabled={true}>
<Text style={[GlobalStyleSheet.textTouchableBarDisabled]}>CONNECT</Text>
</TouchableOpacity>
)
)
}
</View>
</View>
<View style={styles.copyRightsView}>
<Text style={GlobalStyleSheet.copyRightsText}>{this.copyRights()}</Text>
</View>
</ScrollView>
</KeyboardAvoidingView >
</SafeAreaView >
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
height: '100%',
width: '100%',
backgroundColor: COLOR_GRAY_9,
},
headerLogoView: {
height: 50,
backgroundColor: COLOR_GRAY_9,
elevation: 5,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 2,
shadowOffset: { width: 2, height: 2, },
shadowColor: COLOR_BLACK,
shadowOpacity: 0.1,
},
logo: {
height: 40,
width: '80%',
resizeMode: 'contain',
},
viewContainer: {
marginLeft: 15,
marginRight: 15,
paddingBottom: 10
},
copyRightsView: {
alignItems: 'center',
minHeight: 40,
paddingBottom: 5,
},
scrollViewStyle: {
flex: 1,
height: '100%',
paddingTop: 10
},
});
I am trying to use firebase and perform a search. The trouble I am having is when I type the search text the list data isn't being updated.
Below is the code I have come up with
componentDidMount() {
this.setState({loading: true});
var merchants = new Array;
merchantsRef.once('value').then((snapshot) => {
snapshot.forEach((child) => {
merchants.push({
id: child.val().id,
type: child.val().type,
attributes: {
coming_soon: child.val().attributes.coming_soon,
featured_image_url: child.val().attributes.featured_image_url,
has_locations: child.val().attributes.has_locations,
highlight: child.val().attributes.highlight,
logo_url: child.val().attributes.logo_url,
main_image_url: child.val().attributes.main_image_url,
name: child.val().attributes.name,
offer_active: child.val().attributes.offer_active,
offer_cta_title: child.val().attributes.offer_cta_title,
offer_ends_at: child.val().attributes.offer_ends_at,
offer_starts_at: child.val().attributes.offer_starts_at,
offer_teaser: child.val().attributes.offer_teaser,
offer_terms: child.val().attributes.offer_terms,
offer_text: child.val().attributes.offer_text,
offer_url: child.val().attributes.offer_url,
permalink: child.val().attributes.permalink,
shop_url: child.val().attributes.shop_url,
},
_key: child.key
})
})
this.setState({
data: merchants,
loading: false,
})
// console.log(this.state.data)
}).catch((error) => {
console.log('Error fetching retailer data:', error)
})
}
searchFilterFunction = text => {
merchantsRef.orderByChild('name').startAt(text.toString()).on('value', function(child) {
console.log(child.val());
});
};
_renderEmpty = () => {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator />
</View>
)
}
_renderItem = ({item}) => (
<MerchantRow data={item} />
)
_keyExtractor = (item, index) => item._key;
render() {
if (this.state.loading) {
console.log("Loading")
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<ActivityIndicator
animating
size="large"
/>
<Text>Fetching shops...</Text>
</View>
)
}
return (
<View style={styles.container}>
<SearchBar
placeholder='Search for retailers...'
containerStyle={{backgroundColor: Colors.blue, borderTopWidth: 0, borderBottomWidth: 0}}
inputStyle={{backgroundColor: Colors.snow}}
onChangeText={text => this.searchFilterFunction(text)}
autoCorrect={false}
/>
<ScrollView style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this._renderItem.bind(this)}
keyExtractor={this._keyExtractor}
initialNumToRender={9}
ItemSeparatorComponent={this._renderSeparator}
removeClippedSubviews={false}
ListEmptyComponent={this._renderEmpty}
/>
</ScrollView>
</View>
)
}
#Paul'Whippet'McGuane, good to know. That's likely because the context of this isn't defined. In order to maintain the context of the keyword this, you can modify the searchFilterFunction like so:
searchFilterFunction = text => {
const that = this;
merchantsRef.orderByChild('name').startAt(text.toString()).on('value', function(child) {
console.log(child.val());
const val = child.val();
that.setState({ data: val });
});
};