Open hugoseri opened 1 year ago
Hello @hugoseri
I will be glad to help you, could you please provide your local code with such issue?
Regards, Vlad
To fix this issue, you can create a ref using the useRef hook and assign it to the Autocomplete component, like so:
const autocompleteRef = React.useRef(null);
<Autocomplete
placeholder='For example, Star Wars'
value={query}
placement='inner top'
onChangeText={onChangeText}
onSelect={onSelect}
ref={autocompleteRef}
>
By adding ref={autocompleteRef} to the Autocomplete component and creating a autocompleteRef using React.useRef(null), the input field should now be focused correctly.
We will update our showcase for AutoComplete, thank you!
this is still happening, if I type an option that is not there in the list of options, type out then try to focus the Autocomplete again it just refuses to show the keypad
@SteveSB please notice that PR is not merged yet :)
That PR just updates the docs/samples to show including a ref though, unless I'm missing something(?).
I seem to be seeing the same behavior on Android, where tapping an Autocomplete
text field will focus it (and bring up the AutocompleteItem
select list) but won't bring up the keyboard unless the Autocomplete
text field is tapped a 2nd time.
I only see this on Android (iOS brings up keyboard on initial tap). I already have a ref in place for Autocomplete
which is called for various things.
Edit: I'm also seeing the same behavior as @SteveSB, where if you enter text that won't match at least one option and then the component is blurred, it will not ever allow it to be focused again. (both Android and iOS)
It seems there are a couple bugs involved here with Autocomplete:
1) Regarding not being able to focus/edit the Autocomplete field again once it has some text entered which doesn't result in any item matches, that involves this.state.listVisible
being used to determine if the Popover
containing the Input
and List
components is visible. Once there is text in the Input
that doesn't result in a match, the Popover
can't be visible again currently.
2) Regarding the keyboard not coming up on Android when Autocomplete is initially focused (without a 2nd tap), that seems to be an issue with RN's Modal -- which UI Kitten uses now. There is a workaround here using a setTimeout
on onShow
, but since that's not exposed for Autocomplete
it will require a change in UI Kitten. I did try it manually in Autocomplete.component.tsx
and it did work though.
I am also running into this issue. When you have an async autocomplete so you dont have any results when you are first entering text it results in not being able to select the text field at all. Even with the addition of the useRef because the list is empty it loses focus and cannot regain it. This is even when using the example you gave. There used to be a kinda hacky workaround for this behavior but it no longer seems to work. https://github.com/akveo/react-native-ui-kitten/issues/1117
import React, { useState, useEffect, useRef } from 'react';
import AwesomeDebouncePromise from 'awesome-debounce-promise';
import { Autocomplete, AutocompleteItem } from '@ui-kitten/components';
import { SafeAreaView } from 'react-native';
const requestData = () => fetch('https://reactnative.dev/movies.json');
const requestDataWithDebounce = AwesomeDebouncePromise(requestData, 400);
export default function CreateEventScreen() {
const autocompleteRef = useRef(null);
const [query, setQuery] = useState(null);
const [data, setData] = useState([]);
const updateData = () => {
void requestDataWithDebounce()
.then(response => response.json())
.then(json => json.movies)
.then(applyFilter)
.then(setData);
};
useEffect(updateData, [query]);
const onSelect = (index) => {
setQuery(data[index].title);
};
const onChangeText = (nextQuery) => {
setQuery(nextQuery);
};
const applyFilter = (options) => {
return options.filter(item => item.title.toLowerCase().includes(query.toLowerCase()));
};
const renderOption = (item, index) => (
<AutocompleteItem
key={index}
title={item.title}
/>
);
return (
<SafeAreaView style={{ flex: 1}}>
<Autocomplete
ref={autocompleteRef}
placeholder='For example, Star Wars'
value={query}
placement='inner top'
onChangeText={onChangeText}
onSelect={onSelect}
>
{data.map(renderOption)}
</Autocomplete>
</SafeAreaView>
);
};
You can get around this limitation by setting some initial data:
const [data, setData] = useState(["title": "Loading..."]);
Additionally, and happy to open another bug for this the autocomplete box's width is all off:
There are still hacky ways around this also -- which I'm sad to say I'm having to do currently. As the Autocomplete
component is a class component you can extend it and override things like setOptionsListVisible()
to remove or tweak the hasData
check it has as needed. I'm also adding the onShow
workaround for Android to show keyboard on first tap and trying to get onBlur
to report properly. It's not perfect, and feels ugly, but is an option to help things function better for now.
@fzf if you give your Autocomplete component a pixel width (either directly or as a calculated % of screen width) it should display better. I think what you're seeing is another effect of Kitten UI moving to React Native's modals which introduced some quirks that need fixing. (Like the Android keyboard issue above).
Any updates? On Android and iOS I also can't seem to select/focus on the autocomplete input field to typ in text (version 5.3.1).
Extra info: I changed ui-kitten back to v5.1.2, the version I used before, and I still have the problem. My guess is that is has to do with the react native upgrade from v0.70.6 to v0.72.0.
Can someone give me a status update on this bug? Any time indication for the fix? If it takes to long to fix I'll need to find another solution.
What's the current status of this bug? This is a showstopper for us now :( . @Codelica or anyone else do you mind sharing your code snippet? Don't mind it's a hack just want to tide over the issue for now.
@varun85jobs I have a pretty customized use of this component (and I haven't looks at this in months) so I'm not 100% this will be a drop-in workaround for you. Also it is a 100% hack overriding private class methods, etc.. :) but this is the class I'm using:
import {Autocomplete, Popover, List} from '@ui-kitten/components';
// FIXME: Hack to deal with Autocomplete bugs now that Kitten UI uses React modals
class PatchedAutocomplete extends Autocomplete {
// FIXME: onBlur not working correctly
// See: https://github.com/akveo/react-native-ui-kitten/issues/1755
blur = () => {
console.log(`Autocomplete: Overridden blur() called`);
this.inputRef.current?.blur();
this.props.onBlur?.(); // Added
};
// FIXME: Keyboard not showing on Android without second touch
// See: https://github.com/akveo/react-native-ui-kitten/issues/1744
// See: https://github.com/react-native-modal/react-native-modal/issues/516#issuecomment-997961846
onShow = () => {
if (Platform.OS == 'android') {
setTimeout(() => {
this.inputRef.current?.blur();
this.inputRef.current?.focus();
}, 100);
}
}
render() {
const { placement, children, testID, ...inputProps } = this.props;
return (
<Popover
style={styles.popover}
placement={placement}
testID={testID}
visible={this.state.listVisible}
fullWidth={true}
anchor={() => this.renderAnchorInputElement(inputProps)}
onBackdropPress={this.onBackdropPress}
onShow={this.onShow}
>
<View>
{this.renderInputElement(inputProps)}
<List
style={styles.list}
keyboardShouldPersistTaps='always'
data={this.data}
bounces={false}
renderItem={this.renderItem}
/>
</View>
</Popover>
);
}
}
And then in an onBlur()
handler (now that it's working with the hack above) I check to make sure what's been entered is either nothing or matches an item -- if not I RN alert()
the user and clear the value.
Thanks @Codelica for sharing the snippet., however this didn't work for me. I had to use another lib for this. :(
I found a solution following @fzf idea of adding an element to the beginning of the array but also hiding it from the UI.
I share the complete code in case it could be useful to someone.
import React, {useCallback, useMemo} from 'react';
import {Autocomplete, AutocompleteItem, Text} from '@ui-kitten/components';
import {Dimensions} from 'react-native';
interface IMovie {
id: number;
title: string;
visible: boolean;
}
//Simulate data base
const db: IMovie[] = [
{id: 1, title: 'Star Wars', visible: true},
{id: 2, title: 'Back to the Future', visible: true},
{id: 3, title: 'The Matrix', visible: true},
{id: 4, title: 'Inception', visible: true},
{id: 5, title: 'Interstellar', visible: true},
];
//Simulate data base query
const filter = (item: IMovie, query: string): boolean =>
item.title.toLowerCase().includes(query.toLowerCase());
export const Test = (): React.ReactElement => {
const [movie, setMovie] = React.useState<string>('');
const [movies, setMovies] = React.useState<IMovie[]>([]);
const onSelect = useCallback(
(index: number): void => {
setMovie(updatedMovies[index].title);
},
[movies],
);
const onChangeText = useCallback((query: string): void => {
if (query.length === 0) {
setMovie('');
setMovies([]);
} else {
setMovie(query);
setMovies(db.filter(item => filter(item, query)));
}
}, []);
const renderAutocompleteItem = useCallback(
(item: IMovie, index: number) => (
<AutocompleteItem
key={index}
style={[!item.visible ? {display: 'none'} : {}]}
title={item.title}
/>
),
[movies],
);
const updatedMovies: IMovie[] = useMemo(() => {
const movs: IMovie[] = [
{
id: 0,
title: '',
visible: false,
},
];
movies.forEach(u => {
movs.push({
id: u.id,
title: u.title,
visible: u.visible,
});
});
return movs;
}, [movies]);
return (
<Autocomplete
status="primary"
size="large"
label="Movies"
placeholder="Search movies"
value={movie}
placement="inner top"
onSelect={onSelect}
onChangeText={onChangeText}
style={[
{
width: Dimensions.get('screen').width - 50,
},
]}>
{updatedMovies.map(renderAutocompleteItem)}
</Autocomplete>
);
};
It seems there are a couple bugs involved here with Autocomplete:
1. Regarding **not being able to focus/edit the Autocomplete field again once it has some text entered which doesn't result in any item matches**, that involves `this.state.listVisible` being used to determine if the `Popover` containing the `Input` and `List` components is visible. Once there is text in the `Input` that doesn't result in a match, the `Popover` can't be visible again currently.
A workaround to this is including the query text as a new option from the items.
const defaultOptions = ['house', 'car', 'ball']
const [content, setContent] = React.useState({
query: undefined as string | undefined,
items: defaultOptions,
});
const onChangeText = useCallback(
(query: string) => {
const items = defaultOptions.filter(item => item.toLowerCase().includes(query.toLowerCase()))
// If there is any alternative, show them
items.length > 0
? setContent({query, items})
// Else, show the query string as a new option
: setContent({query, items: [query]});
},
[defaultOptions],
);
<Autocomplete
//...
onChangeText={onChangeText}
>
{items.map(content => <AutocompleteItem key={content} title={content} />}
</Autocomplete>
🐛 Bug Report
To Reproduce
Steps to reproduce the behavior: Try using the autocomplete async showcase from the docs: https://akveo.github.io/react-native-ui-kitten/docs/assets/playground-build/#/AutocompleteAsync
I first had the issue on my local project and tried to investigate what is happening. It seems to happen when there is no
<AutocompleteItem/>
to<Autocomplete/>
element (this should be handled as it may happen when the input text doesn't match any of the results).Expected behavior
When clicking on the input, it should become focused, and I should be able to enter my text. However, the input doesn't focus and I can't enter anything.
I first had the issue on my local project and tried to investigate what is happening. It seems to happen when there is no
<AutocompleteItem/>
children to<Autocomplete/>
element.Link to runnable example or repository (highly encouraged)
https://akveo.github.io/react-native-ui-kitten/docs/assets/playground-build/#/AutocompleteAsync
UI Kitten and Eva version
Environment information