Open jahanzaib5244 opened 7 months ago
Facing this issue as well. Any resolutions yet?
index 99a2a13..6640f00 100644
--- a/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js
+++ b/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js
@@ -13,7 +13,6 @@ import React, {
} from 'react';
import {
ActivityIndicator,
- FlatList,
Image,
Keyboard,
Platform,
@@ -22,8 +21,10 @@ import {
StyleSheet,
Text,
TextInput,
+ TouchableOpacity,
View,
} from 'react-native';
+import { FlatList } from 'react-native-gesture-handler';
const defaultStyles = {
container: {
@@ -258,6 +259,7 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
};
const _onPress = (rowData) => {
+ console.log('pressed')
if (rowData.isPredefinedPlace !== true && props.fetchDetails === true) {
if (rowData.isLoading === true) {
// already requesting
@@ -645,19 +647,11 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
return null;
};
- const _renderRow = (rowData = {}, index) => {
+ const _renderRow =useCallback((rowData = {}, index) => {
+ console.log('rendered')
return (
- <ScrollView
- contentContainerStyle={
- props.isRowScrollable ? { minWidth: '100%' } : { width: '100%' }
- }
- scrollEnabled={props.isRowScrollable}
- keyboardShouldPersistTaps={props.keyboardShouldPersistTaps}
- horizontal={true}
- showsHorizontalScrollIndicator={false}
- showsVerticalScrollIndicator={false}
- >
<Pressable
+ key={Math.random().toString(36)}
style={({ hovered, pressed }) => [
props.isRowScrollable ? { minWidth: '100%' } : { width: '100%' },
{
@@ -682,9 +676,9 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
{_renderRowData(rowData, index)}
</View>
</Pressable>
- </ScrollView>
);
- };
+ },[props]);
+
const _renderSeparator = (sectionID, rowID) => {
if (rowID === dataSource.length - 1) {
@@ -785,46 +779,24 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
}
};
- const _getFlatList = () => {
- const keyGenerator = () => Math.random().toString(36).substr(2, 10);
+ const _getFlatList =useCallback( () => {
if (
- supportedPlatform() &&
- (stateText !== '' ||
- props.predefinedPlaces.length > 0 ||
- props.currentLocation === true) &&
+ stateText !== '' &&
listViewDisplayed === true
) {
return (
- <FlatList
- nativeID='result-list-id'
- scrollEnabled={!props.disableScroll}
- style={[
- props.suppressDefaultStyles ? {} : defaultStyles.listView,
- props.styles.listView,
- ]}
- data={dataSource}
- keyExtractor={keyGenerator}
- extraData={[dataSource, props]}
- ItemSeparatorComponent={_renderSeparator}
- renderItem={({ item, index }) => _renderRow(item, index)}
- ListEmptyComponent={
- listLoaderDisplayed
- ? props.listLoaderComponent
- : stateText.length > props.minLength && props.listEmptyComponent
- }
- ListHeaderComponent={
- props.renderHeaderComponent &&
- props.renderHeaderComponent(stateText)
- }
- ListFooterComponent={_renderPoweredLogo}
- {...props}
- />
+ <View style={{zIndex:0,}} >
+ {[...dataSource].slice(0,5).map((item,index)=>{
+ return _renderRow(item, index)
+ })}
+ </View>
+
);
}
return null;
- };
+ },[dataSource]);
let {
onFocus,
@@ -835,6 +807,8 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
...userProps
} = props.textInputProps;
const TextInputComp = InputComp || TextInput;
+ console.log('rendered')
+
return (
<View
style={[
@@ -882,9 +856,9 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
{_renderRightButton()}
</View>
)}
- {props.inbetweenCompo}
+ {/* {props.inbetweenCompo} */}
{_getFlatList()}
- {props.children}
+ {/* {props.children} */}
</View>
);
});
@juzerdhinoj-dimiour you can use this patch file and the issue will be resolved. I replaced Flatlist with map and it worked. Still not get why onPress was not working inside Flatlist
Will this disrupt the currently working iOS functionality?
index 99a2a13..6640f00 100644 --- a/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js +++ b/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js @@ -13,7 +13,6 @@ import React, { } from 'react'; import { ActivityIndicator, - FlatList, Image, Keyboard, Platform, @@ -22,8 +21,10 @@ import { StyleSheet, Text, TextInput, + TouchableOpacity, View, } from 'react-native'; +import { FlatList } from 'react-native-gesture-handler'; const defaultStyles = { container: { @@ -258,6 +259,7 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { }; const _onPress = (rowData) => { + console.log('pressed') if (rowData.isPredefinedPlace !== true && props.fetchDetails === true) { if (rowData.isLoading === true) { // already requesting @@ -645,19 +647,11 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { return null; }; - const _renderRow = (rowData = {}, index) => { + const _renderRow =useCallback((rowData = {}, index) => { + console.log('rendered') return ( - <ScrollView - contentContainerStyle={ - props.isRowScrollable ? { minWidth: '100%' } : { width: '100%' } - } - scrollEnabled={props.isRowScrollable} - keyboardShouldPersistTaps={props.keyboardShouldPersistTaps} - horizontal={true} - showsHorizontalScrollIndicator={false} - showsVerticalScrollIndicator={false} - > <Pressable + key={Math.random().toString(36)} style={({ hovered, pressed }) => [ props.isRowScrollable ? { minWidth: '100%' } : { width: '100%' }, { @@ -682,9 +676,9 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { {_renderRowData(rowData, index)} </View> </Pressable> - </ScrollView> ); - }; + },[props]); + const _renderSeparator = (sectionID, rowID) => { if (rowID === dataSource.length - 1) { @@ -785,46 +779,24 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { } }; - const _getFlatList = () => { - const keyGenerator = () => Math.random().toString(36).substr(2, 10); + const _getFlatList =useCallback( () => { if ( - supportedPlatform() && - (stateText !== '' || - props.predefinedPlaces.length > 0 || - props.currentLocation === true) && + stateText !== '' && listViewDisplayed === true ) { return ( - <FlatList - nativeID='result-list-id' - scrollEnabled={!props.disableScroll} - style={[ - props.suppressDefaultStyles ? {} : defaultStyles.listView, - props.styles.listView, - ]} - data={dataSource} - keyExtractor={keyGenerator} - extraData={[dataSource, props]} - ItemSeparatorComponent={_renderSeparator} - renderItem={({ item, index }) => _renderRow(item, index)} - ListEmptyComponent={ - listLoaderDisplayed - ? props.listLoaderComponent - : stateText.length > props.minLength && props.listEmptyComponent - } - ListHeaderComponent={ - props.renderHeaderComponent && - props.renderHeaderComponent(stateText) - } - ListFooterComponent={_renderPoweredLogo} - {...props} - /> + <View style={{zIndex:0,}} > + {[...dataSource].slice(0,5).map((item,index)=>{ + return _renderRow(item, index) + })} + </View> + ); } return null; - }; + },[dataSource]); let { onFocus, @@ -835,6 +807,8 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { ...userProps } = props.textInputProps; const TextInputComp = InputComp || TextInput; + console.log('rendered') + return ( <View style={[ @@ -882,9 +856,9 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { {_renderRightButton()} </View> )} - {props.inbetweenCompo} + {/* {props.inbetweenCompo} */} {_getFlatList()} - {props.children} + {/* {props.children} */} </View> ); });
@juzerdhinoj-dimiour you can use this patch file and the issue will be resolved. I replaced Flatlist with map and it worked. Still not get why onPress was not working inside Flatlist
Will this disrupt the currently working iOS functionality?
index 99a2a13..6640f00 100644 --- a/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js +++ b/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js @@ -13,7 +13,6 @@ import React, { } from 'react'; import { ActivityIndicator, - FlatList, Image, Keyboard, Platform, @@ -22,8 +21,10 @@ import { StyleSheet, Text, TextInput, + TouchableOpacity, View, } from 'react-native'; +import { FlatList } from 'react-native-gesture-handler'; const defaultStyles = { container: { @@ -258,6 +259,7 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { }; const _onPress = (rowData) => { + console.log('pressed') if (rowData.isPredefinedPlace !== true && props.fetchDetails === true) { if (rowData.isLoading === true) { // already requesting @@ -645,19 +647,11 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { return null; }; - const _renderRow = (rowData = {}, index) => { + const _renderRow =useCallback((rowData = {}, index) => { + console.log('rendered') return ( - <ScrollView - contentContainerStyle={ - props.isRowScrollable ? { minWidth: '100%' } : { width: '100%' } - } - scrollEnabled={props.isRowScrollable} - keyboardShouldPersistTaps={props.keyboardShouldPersistTaps} - horizontal={true} - showsHorizontalScrollIndicator={false} - showsVerticalScrollIndicator={false} - > <Pressable + key={Math.random().toString(36)} style={({ hovered, pressed }) => [ props.isRowScrollable ? { minWidth: '100%' } : { width: '100%' }, { @@ -682,9 +676,9 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { {_renderRowData(rowData, index)} </View> </Pressable> - </ScrollView> ); - }; + },[props]); + const _renderSeparator = (sectionID, rowID) => { if (rowID === dataSource.length - 1) { @@ -785,46 +779,24 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { } }; - const _getFlatList = () => { - const keyGenerator = () => Math.random().toString(36).substr(2, 10); + const _getFlatList =useCallback( () => { if ( - supportedPlatform() && - (stateText !== '' || - props.predefinedPlaces.length > 0 || - props.currentLocation === true) && + stateText !== '' && listViewDisplayed === true ) { return ( - <FlatList - nativeID='result-list-id' - scrollEnabled={!props.disableScroll} - style={[ - props.suppressDefaultStyles ? {} : defaultStyles.listView, - props.styles.listView, - ]} - data={dataSource} - keyExtractor={keyGenerator} - extraData={[dataSource, props]} - ItemSeparatorComponent={_renderSeparator} - renderItem={({ item, index }) => _renderRow(item, index)} - ListEmptyComponent={ - listLoaderDisplayed - ? props.listLoaderComponent - : stateText.length > props.minLength && props.listEmptyComponent - } - ListHeaderComponent={ - props.renderHeaderComponent && - props.renderHeaderComponent(stateText) - } - ListFooterComponent={_renderPoweredLogo} - {...props} - /> + <View style={{zIndex:0,}} > + {[...dataSource].slice(0,5).map((item,index)=>{ + return _renderRow(item, index) + })} + </View> + ); } return null; - }; + },[dataSource]); let { onFocus, @@ -835,6 +807,8 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { ...userProps } = props.textInputProps; const TextInputComp = InputComp || TextInput; + console.log('rendered') + return ( <View style={[ @@ -882,9 +856,9 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { {_renderRightButton()} </View> )} - {props.inbetweenCompo} + {/* {props.inbetweenCompo} */} {_getFlatList()} - {props.children} + {/* {props.children} */} </View> ); });
@juzerdhinoj-dimiour you can use this patch file and the issue will be resolved. I replaced Flatlist with map and it worked. Still not get why onPress was not working inside Flatlist
No, it will not reflect the ios.
@jahanzaib5244 Instead of the change list, can you please share the actual file? It will be a better reference point.
@jahanzaib5244 Instead of the change list, can you please share the actual file? It will be a better reference point.
import PropTypes from 'prop-types';
import Qs from 'qs';
import React, {
forwardRef,
useMemo,
useEffect,
useImperativeHandle,
useRef,
useState,
useCallback,
} from 'react';
import {
ActivityIndicator,
Image,
Keyboard,
Platform,
Pressable,
StyleSheet,
Text,
TextInput,
View,
} from 'react-native';
const defaultStyles = {
container: {
flex: 1,
},
textInputContainer: {
flexDirection: 'row',
},
textInput: {
backgroundColor: '#FFFFFF',
height: 44,
borderRadius: 5,
paddingVertical: 5,
paddingHorizontal: 10,
fontSize: 15,
flex: 1,
marginBottom: 5,
},
listView: {},
row: {
backgroundColor: '#FFFFFF',
padding: 13,
minHeight: 44,
flexDirection: 'row',
},
loader: {
flexDirection: 'row',
justifyContent: 'flex-end',
height: 20,
},
description: {},
separator: {
height: StyleSheet.hairlineWidth,
backgroundColor: '#c8c7cc',
},
poweredContainer: {
justifyContent: 'flex-end',
alignItems: 'center',
borderBottomRightRadius: 5,
borderBottomLeftRadius: 5,
borderColor: '#c8c7cc',
borderTopWidth: 0.5,
},
powered: {},
};
export const GooglePlacesAutocomplete = forwardRef((props, ref) => {
let _results = [];
let _requests = [];
const hasNavigator = () => {
if (navigator?.geolocation) {
return true;
} else {
console.warn(
'If you are using React Native v0.60.0+ you must follow these instructions to enable currentLocation: https://git.io/Jf4AR',
);
return false;
}
};
const buildRowsFromResults = useCallback(
(results, text) => {
let res = [];
const shouldDisplayPredefinedPlaces = text
? results.length === 0 && text.length === 0
: results.length === 0;
if (
shouldDisplayPredefinedPlaces ||
props.predefinedPlacesAlwaysVisible === true
) {
res = [
...props.predefinedPlaces.filter(
(place) => place?.description.length,
),
];
if (props.currentLocation === true && hasNavigator()) {
res.unshift({
description: props.currentLocationLabel,
isCurrentLocation: true,
});
}
}
res = res.map((place) => ({
...place,
isPredefinedPlace: true,
}));
return [...res, ...results];
},
[
props.currentLocation,
props.currentLocationLabel,
props.predefinedPlaces,
props.predefinedPlacesAlwaysVisible,
],
);
const getRequestUrl = useCallback((requestUrl) => {
if (requestUrl) {
if (requestUrl.useOnPlatform === 'all') {
return requestUrl.url;
}
if (requestUrl.useOnPlatform === 'web') {
return Platform.select({
web: requestUrl.url,
default: 'https://maps.googleapis.com/maps/api',
});
}
} else {
return 'https://maps.googleapis.com/maps/api';
}
}, []);
const getRequestHeaders = (requestUrl) => {
return requestUrl?.headers || {};
};
const setRequestHeaders = (request, headers) => {
Object.keys(headers).map((headerKey) =>
request.setRequestHeader(headerKey, headers[headerKey]),
);
};
const [stateText, setStateText] = useState('');
const [dataSource, setDataSource] = useState(buildRowsFromResults([]));
const [listViewDisplayed, setListViewDisplayed] = useState(
props.listViewDisplayed === 'auto' ? false : props.listViewDisplayed,
);
const [url, setUrl] = useState(getRequestUrl(props.requestUrl));
const [listLoaderDisplayed, setListLoaderDisplayed] = useState(false);
const inputRef = useRef();
useEffect(() => {
setUrl(getRequestUrl(props.requestUrl));
}, [getRequestUrl, props.requestUrl]);
useEffect(() => {
// This will load the search results after the query object ref gets changed
_handleChangeText(stateText);
return () => {
_abortRequests();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.query]);
useEffect(() => {
// Update dataSource if props.predefinedPlaces changed
setDataSource(buildRowsFromResults([]));
}, [buildRowsFromResults, props.predefinedPlaces]);
useImperativeHandle(ref, () => ({
setAddressText: (address) => {
setStateText(address);
},
getAddressText: () => stateText,
blur: () => inputRef.current.blur(),
focus: () => inputRef.current.focus(),
isFocused: () => inputRef.current.isFocused(),
clear: () => inputRef.current.clear(),
getCurrentLocation,
}));
const requestShouldUseWithCredentials = () =>
url === 'https://maps.googleapis.com/maps/api';
const _abortRequests = () => {
_requests.map((i) => {
i.onreadystatechange = null;
i.abort();
});
_requests = [];
};
const supportedPlatform = () => {
if (Platform.OS === 'web' && !props.requestUrl) {
console.warn(
'This library cannot be used for the web unless you specify the requestUrl prop. See https://git.io/JflFv for more for details.',
);
return false;
} else {
return true;
}
};
const getCurrentLocation = () => {
let options = {
enableHighAccuracy: false,
timeout: 20000,
maximumAge: 1000,
};
if (props.enableHighAccuracyLocation && Platform.OS === 'android') {
options = {
enableHighAccuracy: true,
timeout: 20000,
};
}
const getCurrentPosition =
navigator.geolocation.getCurrentPosition ||
navigator.geolocation.default.getCurrentPosition;
getCurrentPosition &&
getCurrentPosition(
(position) => {
if (props.nearbyPlacesAPI === 'None') {
let currentLocation = {
description: props.currentLocationLabel,
geometry: {
location: {
lat: position.coords.latitude,
lng: position.coords.longitude,
},
},
};
_disableRowLoaders();
props.onPress(currentLocation, currentLocation);
} else {
_requestNearby(position.coords.latitude, position.coords.longitude);
}
},
(error) => {
_disableRowLoaders();
console.error(error.message);
},
options,
);
};
const _onPress = (rowData) => {
if (rowData.isPredefinedPlace !== true && props.fetchDetails === true) {
if (rowData.isLoading === true) {
// already requesting
return;
}
Keyboard.dismiss();
_abortRequests();
// display loader
_enableRowLoader(rowData);
// fetch details
const request = new XMLHttpRequest();
_requests.push(request);
request.timeout = props.timeout;
request.ontimeout = props.onTimeout;
request.onreadystatechange = () => {
if (request.readyState !== 4) return;
if (request.status === 200) {
const responseJSON = JSON.parse(request.responseText);
if (responseJSON.status === 'OK') {
// if (_isMounted === true) {
const details = responseJSON.result;
_disableRowLoaders();
_onBlur();
setStateText(_renderDescription(rowData));
delete rowData.isLoading;
props.onPress(rowData, details);
// }
} else {
_disableRowLoaders();
if (props.autoFillOnNotFound) {
setStateText(_renderDescription(rowData));
delete rowData.isLoading;
}
if (!props.onNotFound) {
console.warn(
'google places autocomplete: ' + responseJSON.status,
);
} else {
props.onNotFound(responseJSON);
}
}
} else {
_disableRowLoaders();
if (!props.onFail) {
console.warn(
'google places autocomplete: request could not be completed or has been aborted',
);
} else {
props.onFail('request could not be completed or has been aborted');
}
}
};
request.open(
'GET',
`${url}/place/details/json?` +
Qs.stringify({
key: props.query.key,
placeid: rowData.place_id,
language: props.query.language,
...props.GooglePlacesDetailsQuery,
}),
);
request.withCredentials = requestShouldUseWithCredentials();
setRequestHeaders(request, getRequestHeaders(props.requestUrl));
request.send();
} else if (rowData.isCurrentLocation === true) {
// display loader
_enableRowLoader(rowData);
setStateText(_renderDescription(rowData));
delete rowData.isLoading;
getCurrentLocation();
} else {
setStateText(_renderDescription(rowData));
_onBlur();
delete rowData.isLoading;
let predefinedPlace = _getPredefinedPlace(rowData);
// sending predefinedPlace as details for predefined places
props.onPress(predefinedPlace, predefinedPlace);
}
};
const _enableRowLoader = (rowData) => {
let rows = buildRowsFromResults(_results);
for (let i = 0; i < rows.length; i++) {
if (
rows[i].place_id === rowData.place_id ||
(rows[i].isCurrentLocation === true &&
rowData.isCurrentLocation === true)
) {
rows[i].isLoading = true;
setDataSource(rows);
break;
}
}
};
const _disableRowLoaders = () => {
// if (_isMounted === true) {
for (let i = 0; i < _results.length; i++) {
if (_results[i].isLoading === true) {
_results[i].isLoading = false;
}
}
setDataSource(buildRowsFromResults(_results));
// }
};
const _getPredefinedPlace = (rowData) => {
if (rowData.isPredefinedPlace !== true) {
return rowData;
}
for (let i = 0; i < props.predefinedPlaces.length; i++) {
if (props.predefinedPlaces[i].description === rowData.description) {
return props.predefinedPlaces[i];
}
}
return rowData;
};
const _filterResultsByTypes = (unfilteredResults, types) => {
if (types.length === 0) return unfilteredResults;
const results = [];
for (let i = 0; i < unfilteredResults.length; i++) {
let found = false;
for (let j = 0; j < types.length; j++) {
if (unfilteredResults[i].types.indexOf(types[j]) !== -1) {
found = true;
break;
}
}
if (found === true) {
results.push(unfilteredResults[i]);
}
}
return results;
};
const _requestNearby = (latitude, longitude) => {
_abortRequests();
if (
latitude !== undefined &&
longitude !== undefined &&
latitude !== null &&
longitude !== null
) {
const request = new XMLHttpRequest();
_requests.push(request);
request.timeout = props.timeout;
request.ontimeout = props.onTimeout;
request.onreadystatechange = () => {
if (request.readyState !== 4) {
setListLoaderDisplayed(true);
return;
}
setListLoaderDisplayed(false);
if (request.status === 200) {
const responseJSON = JSON.parse(request.responseText);
_disableRowLoaders();
if (typeof responseJSON.results !== 'undefined') {
// if (_isMounted === true) {
var results = [];
if (props.nearbyPlacesAPI === 'GoogleReverseGeocoding') {
results = _filterResultsByTypes(
responseJSON.results,
props.filterReverseGeocodingByTypes,
);
} else {
results = responseJSON.results;
}
setDataSource(buildRowsFromResults(results));
// }
}
if (typeof responseJSON.error_message !== 'undefined') {
if (!props.onFail)
console.warn(
'google places autocomplete: ' + responseJSON.error_message,
);
else {
props.onFail(responseJSON.error_message);
}
}
} else {
// console.warn("google places autocomplete: request could not be completed or has been aborted");
}
};
let requestUrl = '';
if (props.nearbyPlacesAPI === 'GoogleReverseGeocoding') {
// your key must be allowed to use Google Maps Geocoding API
requestUrl =
`${url}/geocode/json?` +
Qs.stringify({
latlng: latitude + ',' + longitude,
key: props.query.key,
...props.GoogleReverseGeocodingQuery,
});
} else {
requestUrl =
`${url}/place/nearbysearch/json?` +
Qs.stringify({
location: latitude + ',' + longitude,
key: props.query.key,
...props.GooglePlacesSearchQuery,
});
}
request.open('GET', requestUrl);
request.withCredentials = requestShouldUseWithCredentials();
setRequestHeaders(request, getRequestHeaders(props.requestUrl));
request.send();
} else {
_results = [];
setDataSource(buildRowsFromResults([]));
}
};
const _request = (text) => {
_abortRequests();
if (!url) {
return;
}
if (supportedPlatform() && text && text.length >= props.minLength) {
const request = new XMLHttpRequest();
_requests.push(request);
request.timeout = props.timeout;
request.ontimeout = props.onTimeout;
request.onreadystatechange = () => {
if (request.readyState !== 4) {
setListLoaderDisplayed(true);
return;
}
setListLoaderDisplayed(false);
if (request.status === 200) {
const responseJSON = JSON.parse(request.responseText);
if (typeof responseJSON.predictions !== 'undefined') {
// if (_isMounted === true) {
const results =
props.nearbyPlacesAPI === 'GoogleReverseGeocoding'
? _filterResultsByTypes(
responseJSON.predictions,
props.filterReverseGeocodingByTypes,
)
: responseJSON.predictions;
_results = results;
setDataSource(buildRowsFromResults(results, text));
// }
}
if (typeof responseJSON.error_message !== 'undefined') {
if (!props.onFail)
console.warn(
'google places autocomplete: ' + responseJSON.error_message,
);
else {
props.onFail(responseJSON.error_message);
}
}
} else {
// console.warn("google places autocomplete: request could not be completed or has been aborted");
}
};
if (props.preProcess) {
setStateText(props.preProcess(text));
}
request.open(
'GET',
`${url}/place/autocomplete/json?input=` +
encodeURIComponent(text) +
'&' +
Qs.stringify(props.query),
);
request.withCredentials = requestShouldUseWithCredentials();
setRequestHeaders(request, getRequestHeaders(props.requestUrl));
request.send();
} else {
_results = [];
setDataSource(buildRowsFromResults([]));
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
const debounceData = useMemo(() => debounce(_request, props.debounce), [
props.query,
url,
]);
const _onChangeText = (text) => {
setStateText(text);
debounceData(text);
};
const _handleChangeText = (text) => {
_onChangeText(text);
const onChangeText = props?.textInputProps?.onChangeText;
if (onChangeText) {
onChangeText(text);
}
};
const _getRowLoader = () => {
return <ActivityIndicator animating={true} size='small' />;
};
const _renderRowData = (rowData, index) => {
if (props.renderRow) {
return props.renderRow(rowData, index);
}
return (
<Text
style={[
props.suppressDefaultStyles ? {} : defaultStyles.description,
props.styles.description,
rowData.isPredefinedPlace
? props.styles.predefinedPlacesDescription
: {},
]}
numberOfLines={props.numberOfLines}
>
{_renderDescription(rowData)}
</Text>
);
};
const _renderDescription = (rowData) => {
if (props.renderDescription) {
return props.renderDescription(rowData);
}
return rowData.description || rowData.formatted_address || rowData.name;
};
const _renderLoader = (rowData) => {
if (rowData.isLoading === true) {
return (
<View
style={[
props.suppressDefaultStyles ? {} : defaultStyles.loader,
props.styles.loader,
]}
>
{_getRowLoader()}
</View>
);
}
return null;
};
const _renderRow =useCallback((rowData = {}, index) => {
return (
<Pressable
key={Math.random().toString(36)}
style={({ hovered, pressed }) => [
props.isRowScrollable ? { minWidth: '100%' } : { width: '100%' },
{
backgroundColor: pressed
? props.listUnderlayColor
: hovered
? props.listHoverColor
: undefined,
},
]}
onPress={() =>_onPress(rowData)}
onBlur={_onBlur}
>
<View
style={[
props.suppressDefaultStyles ? {} : defaultStyles.row,
props.styles.row,
rowData.isPredefinedPlace ? props.styles.specialItemRow : {},
]}
>
{_renderLoader(rowData)}
{_renderRowData(rowData, index)}
</View>
</Pressable>
);
},[props]);
const _renderSeparator = (sectionID, rowID) => {
if (rowID === dataSource.length - 1) {
return null;
}
return (
<View
key={`${sectionID}-${rowID}`}
style={[
props.suppressDefaultStyles ? {} : defaultStyles.separator,
props.styles.separator,
]}
/>
);
};
const isNewFocusInAutocompleteResultList = ({
relatedTarget,
currentTarget,
}) => {
if (!relatedTarget) return false;
var node = relatedTarget.parentNode;
while (node) {
if (node.id === 'result-list-id') return true;
node = node.parentNode;
}
return false;
};
const _onBlur = (e) => {
if (e && isNewFocusInAutocompleteResultList(e)) return;
if (!props.keepResultsAfterBlur) {
setListViewDisplayed(false);
}
inputRef?.current?.blur();
};
const _onFocus = () => setListViewDisplayed(true);
const _renderPoweredLogo = () => {
if (!_shouldShowPoweredLogo()) {
return null;
}
return (
<View
style={[
props.suppressDefaultStyles ? {} : defaultStyles.row,
defaultStyles.poweredContainer,
props.styles.poweredContainer,
]}
>
<Image
style={[
props.suppressDefaultStyles ? {} : defaultStyles.powered,
props.styles.powered,
]}
resizeMode='contain'
source={require('./images/powered_by_google_on_white.png')}
/>
</View>
);
};
const _shouldShowPoweredLogo = () => {
if (!props.enablePoweredByContainer || dataSource.length === 0) {
return false;
}
for (let i = 0; i < dataSource.length; i++) {
let row = dataSource[i];
if (
!row.hasOwnProperty('isCurrentLocation') &&
!row.hasOwnProperty('isPredefinedPlace')
) {
return true;
}
}
return false;
};
const _renderLeftButton = () => {
if (props.renderLeftButton) {
return props.renderLeftButton();
}
};
const _renderRightButton = () => {
if (props.renderRightButton) {
return props.renderRightButton();
}
};
const _getFlatList =useCallback( () => {
if (
stateText !== '' &&
listViewDisplayed === true
) {
return (
<View style={{zIndex:0,}} >
{[...dataSource].slice(0,5).map((item,index)=>{
return _renderRow(item, index)
})}
</View>
);
}
return null;
},[dataSource]);
let {
onFocus,
onBlur,
onChangeText,
clearButtonMode,
InputComp,
...userProps
} = props.textInputProps;
const TextInputComp = InputComp || TextInput;
return (
<View
style={[
props.suppressDefaultStyles ? {} : defaultStyles.container,
props.styles.container,
]}
pointerEvents='box-none'
>
{!props.textInputHide && (
<View
style={[
props.suppressDefaultStyles ? {} : defaultStyles.textInputContainer,
props.styles.textInputContainer,
]}
>
{_renderLeftButton()}
<TextInputComp
ref={inputRef}
style={[
props.suppressDefaultStyles ? {} : defaultStyles.textInput,
props.styles.textInput,
]}
value={stateText}
placeholder={props.placeholder}
onFocus={
onFocus
? (e) => {
_onFocus();
onFocus(e);
}
: _onFocus
}
onBlur={
onBlur
? (e) => {
_onBlur(e);
onBlur(e);
}
: _onBlur
}
clearButtonMode={clearButtonMode || 'while-editing'}
onChangeText={_handleChangeText}
{...userProps}
/>
{_renderRightButton()}
</View>
)}
{props.inbetweenCompo}
{_getFlatList()}
{props.children}
</View>
);
});
GooglePlacesAutocomplete.propTypes = {
autoFillOnNotFound: PropTypes.bool,
currentLocation: PropTypes.bool,
currentLocationLabel: PropTypes.string,
debounce: PropTypes.number,
disableScroll: PropTypes.bool,
enableHighAccuracyLocation: PropTypes.bool,
enablePoweredByContainer: PropTypes.bool,
fetchDetails: PropTypes.bool,
filterReverseGeocodingByTypes: PropTypes.array,
GooglePlacesDetailsQuery: PropTypes.object,
GooglePlacesSearchQuery: PropTypes.object,
GoogleReverseGeocodingQuery: PropTypes.object,
inbetweenCompo: PropTypes.object,
isRowScrollable: PropTypes.bool,
keyboardShouldPersistTaps: PropTypes.oneOf(['never', 'always', 'handled']),
listEmptyComponent: PropTypes.element,
listLoaderComponent: PropTypes.element,
listHoverColor: PropTypes.string,
listUnderlayColor: PropTypes.string,
// Must write it this way: https://stackoverflow.com/a/54290946/7180620
listViewDisplayed: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.oneOf(['auto']),
]),
keepResultsAfterBlur: PropTypes.bool,
minLength: PropTypes.number,
nearbyPlacesAPI: PropTypes.string,
numberOfLines: PropTypes.number,
onFail: PropTypes.func,
onNotFound: PropTypes.func,
onPress: PropTypes.func,
onTimeout: PropTypes.func,
placeholder: PropTypes.string,
predefinedPlaces: PropTypes.array,
predefinedPlacesAlwaysVisible: PropTypes.bool,
preProcess: PropTypes.func,
query: PropTypes.object,
renderDescription: PropTypes.func,
renderHeaderComponent: PropTypes.func,
renderLeftButton: PropTypes.func,
renderRightButton: PropTypes.func,
renderRow: PropTypes.func,
requestUrl: PropTypes.shape({
url: PropTypes.string,
useOnPlatform: PropTypes.oneOf(['web', 'all']),
headers: PropTypes.objectOf(PropTypes.string),
}),
styles: PropTypes.object,
suppressDefaultStyles: PropTypes.bool,
textInputHide: PropTypes.bool,
textInputProps: PropTypes.object,
timeout: PropTypes.number,
};
GooglePlacesAutocomplete.defaultProps = {
autoFillOnNotFound: false,
currentLocation: false,
currentLocationLabel: 'Current location',
debounce: 0,
disableScroll: false,
enableHighAccuracyLocation: true,
enablePoweredByContainer: true,
fetchDetails: false,
filterReverseGeocodingByTypes: [],
GooglePlacesDetailsQuery: {},
GooglePlacesSearchQuery: {
rankby: 'distance',
type: 'restaurant',
},
GoogleReverseGeocodingQuery: {},
isRowScrollable: true,
keyboardShouldPersistTaps: 'always',
listHoverColor: '#ececec',
listUnderlayColor: '#c8c7cc',
listViewDisplayed: 'auto',
keepResultsAfterBlur: false,
minLength: 0,
nearbyPlacesAPI: 'GooglePlacesSearch',
numberOfLines: 1,
onFail: () => {},
onNotFound: () => {},
onPress: () => {},
onTimeout: () => console.warn('google places autocomplete: request timeout'),
placeholder: '',
predefinedPlaces: [],
predefinedPlacesAlwaysVisible: false,
query: {
key: 'missing api key',
language: 'en',
types: 'geocode',
},
styles: {},
suppressDefaultStyles: false,
textInputHide: false,
textInputProps: {},
timeout: 20000,
};
GooglePlacesAutocomplete.displayName = 'GooglePlacesAutocomplete';
export default { GooglePlacesAutocomplete };````
@jahanzaib5244 the patch works but it affects the onPress functionality.
After some testing, I found that original code seems to work as well when you turn the keyboard off in Android emulator. Now I need to explore what is causing the conflict with the keyboard popup.
have you tried adding the keyboardShouldPersistTaps="handled"
in the parent component
<ScrollView keyboardShouldPersistTaps="handled">
<View keyboardShouldPersistTaps="handled" >
<GooglePlacesAutocomplete
// your everything
/>
</View>
</ScrollView>
Same issue, keyboardShouldPersistTaps="handled"
doesn't work for me
EDIT: nvm, it did 🚀
<ScrollView keyboardShouldPersistTaps='handled'>
<FlatList
keyboardShouldPersistTaps='handled'
...
@Jheysson You can use this Patch file code `index 99a2a13..6640f00 100644 --- a/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js +++ b/node_modules/react-native-google-places-autocomplete/GooglePlacesAutocomplete.js @@ -13,7 +13,6 @@ import React, { } from 'react'; import { ActivityIndicator,
FlatList, Image, Keyboard, Platform, @@ -22,8 +21,10 @@ import { StyleSheet, Text, TextInput,
TouchableOpacity, View, } from 'react-native'; +import { FlatList } from 'react-native-gesture-handler';
const defaultStyles = { container: { @@ -258,6 +259,7 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { };
const _onPress = (rowData) => {
console.log('pressed') if (rowData.isPredefinedPlace !== true && props.fetchDetails === true) { if (rowData.isLoading === true) { // already requesting @@ -645,19 +647,11 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { return null; };
const _renderRow = (rowData = {}, index) => {
const _renderRow =useCallback((rowData = {}, index) => {
console.log('rendered') return (
<ScrollView
contentContainerStyle={
props.isRowScrollable ? { minWidth: '100%' } : { width: '100%' }
}
scrollEnabled={props.isRowScrollable}
keyboardShouldPersistTaps={props.keyboardShouldPersistTaps}
horizontal={true}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
<Pressable
key={Math.random().toString(36)} style={({ hovered, pressed }) => [ props.isRowScrollable ? { minWidth: '100%' } : { width: '100%' }, { @@ -682,9 +676,9 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { {_renderRowData(rowData, index)}
);
};
},[props]);
const _renderSeparator = (sectionID, rowID) => { if (rowID === dataSource.length - 1) { @@ -785,46 +779,24 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { } };
const _getFlatList = () => {
const keyGenerator = () => Math.random().toString(36).substr(2, 10);
const _getFlatList =useCallback( () => {
if (
supportedPlatform() &&
(stateText !== '' ||
props.predefinedPlaces.length > 0 ||
props.currentLocation === true) &&
stateText !== '' && listViewDisplayed === true ) { return (
<FlatList
nativeID='result-list-id'
scrollEnabled={!props.disableScroll}
style={[
props.suppressDefaultStyles ? {} : defaultStyles.listView,
props.styles.listView,
]}
data={dataSource}
keyExtractor={keyGenerator}
extraData={[dataSource, props]}
ItemSeparatorComponent={_renderSeparator}
renderItem={({ item, index }) => _renderRow(item, index)}
ListEmptyComponent={
listLoaderDisplayed
? props.listLoaderComponent
: stateText.length > props.minLength && props.listEmptyComponent
}
ListHeaderComponent={
props.renderHeaderComponent &&
props.renderHeaderComponent(stateText)
}
ListFooterComponent={_renderPoweredLogo}
{...props}
/>
{[...dataSource].slice(0,5).map((item,index)=>{
return _renderRow(item, index)
})}
); }
return null;
};
},[dataSource]);
let { onFocus, @@ -835,6 +807,8 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { ...userProps } = props.textInputProps; const TextInputComp = InputComp || TextInput;
console.log('rendered')
return ( <View style={[ @@ -882,9 +856,9 @@ export const GooglePlacesAutocomplete = forwardRef((props, ref) => { {_renderRightButton()} )}
{props.inbetweenCompo}
{/ {props.inbetweenCompo} /} {_getFlatList()}
{props.children}
{/ {props.children} /} ); });`
this works for me thanks a lot @jahanzaib5244 but why there is problem still exist? Why not fixed do you know?
I think i got the problem cause of i wrap the google-places-autocomplete with modal so onPress is not working fine but if you add keepResultsAfterBlur={true}
prop to autocomplete it work fine. But still there is exist problem because in my case in first press it hide the keyboard after i need to press again to work onPress function.
@jahanzaib5244 i have the same issue working on ios but not andriod
is there a file or package patch that i can use
I'm using react-native-google-places-autocomplete@2.5.6
when i used the code provided i'm getting this error :
ReferenceError: Property 'debounce' doesn't exist
Same issue @jahanzaib5244 I tried your solution, it work but still not consistent, only first time
@jahanzaib5244 i have the same issue working on ios but not andriod is there a file or package patch that i can use I'm using react-native-google-places-autocomplete@2.5.6 when i used the code provided i'm getting this error :
ReferenceError: Property 'debounce' doesn't exist
You could add
import debounce from 'lodash.debounce'
have you tried adding the
keyboardShouldPersistTaps="handled"
in the parent component<ScrollView keyboardShouldPersistTaps="handled"> <View keyboardShouldPersistTaps="handled" > <GooglePlacesAutocomplete // your everything /> </View> </ScrollView>
Thanks, this was the simple and obvious (in retrospect) issue. All fixed!
@OFD16
I have the same issue with keepResultsAfterBlur having to tap away the keyboard and then select with the onPress
<GooglePlacesAutocomplete
placeholder="Search for an address"
fetchDetails
keepResultsAfterBlur // This ensures that a user can tap the dropdown on android after using a tap to dismiss the keyboard
keyboardShouldPersistTaps="handled"
// rest of the code
</GooglePlacesAutocomplete>
onPress not working on android
i am using a map and GooglePlacesAutocomplete input on ios it is working perfectly but on android i am unable to pick the location .
Please provide a FULLY REPRODUCIBLE example.
Click to expand!
```javascript const GooglePlacesInput: React.FCPlease remember to remove you google API key from the code you provide here
Additional context
Add any other context about the problem here, screenshots etc