My Typeahead component:
<Typeahead
ref="SubjectTypeahead"
placeholder="Search Subjects"
onChange={this.onSearchSubjects}
options={subjectNames}/>
My onChange function:
onSearchSubjects = (values) => {
if (values.length > 0) {
this.refs.SubjectTypeahead.getInstance().clear()
this.props.onSearchSubjects(values[0])
}
}
When selecting a value form the typeahead, my onChange method gets called, but the value selected doesn't get cleared.
Any idea what I might be doing wrong?
Thanks
Hi. Questions like this are more appropriate for a forum like StackOverflow since your question will remain open and potentially help others facing the same issue. Posting there also helps me keep the issues queue manageable and limited to bugs and feature requests. Feel free to post a link to your SO question on this thread and I'd be happy to try and help. Thanks.
Okay. But after further testing, I do believe that this is a bug. I am able to clear the typeahead field if I do it from a button onClick function, per your examples. However, from the onChange callback, the field is not cleared.
Interestingly, the field is cleared if I don’t do the length check. But then I get the infinite loop that you warn of in your API documentation.
On Jul 20, 2017, at 10:11 PM, Eric Giovanola notifications@github.com wrote:
Hi. Questions like this are more appropriate for a forum like StackOverflow since your question will remain open and potentially help others facing the same issue. Posting there also helps me keep the issues queue manageable and limited to bugs and feature requests. Feel free to post a link to your SO question on this thread and I'd be happy to try and help. Thanks.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub https://github.com/ericgio/react-bootstrap-typeahead/issues/211#issuecomment-316890294, or mute the thread https://github.com/notifications/unsubscribe-auth/AAoGamrgJ2ixhz9oxWsQBaTyCs7wjPIBks5sQBbPgaJpZM4OeqeO.
Just to give you some context, the behavior that I want to duplicate is the behavior you get when you do a search at Wikipedia (https://en.wikipedia.org/wiki https://en.wikipedia.org/wiki). If you search for a topic there, after you make a selection the search field is cleared and you are taken to the topic page.
On Jul 20, 2017, at 10:11 PM, Eric Giovanola notifications@github.com wrote:
Hi. Questions like this are more appropriate for a forum like StackOverflow since your question will remain open and potentially help others facing the same issue. Posting there also helps me keep the issues queue manageable and limited to bugs and feature requests. Feel free to post a link to your SO question on this thread and I'd be happy to try and help. Thanks.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub https://github.com/ericgio/react-bootstrap-typeahead/issues/211#issuecomment-316890294, or mute the thread https://github.com/notifications/unsubscribe-auth/AAoGamrgJ2ixhz9oxWsQBaTyCs7wjPIBks5sQBbPgaJpZM4OeqeO.
I'm pretty confident it's not a bug, as I've implemented behavior similar to what you're describing in a project (minus the redirect part). If you post a more complete code example on SO, I can try to help you.
@ChuckIrvine I had the same issue, with AsyncTypeahead and onChange , this is how I solved it:
setTimeout(() => this.refs.SubjectTypeahead.getInstance().clear(), 0);
Very cool. I’ve been meaning to bring that off the back burner. To get around the problem, I created a button that the user could use to clear the field - not pretty. I wonder if the typeahead author would consider this problem a bug? Anyway, Thanks!
On Aug 18, 2017, at 11:47 AM, Anton O. notifications@github.com wrote:
@ChuckIrvine https://github.com/chuckirvine I had the same issue, with AsyncTypeahead and onChange , this is how I solved it:
setTimeout(() => this.refs.SubjectTypeahead.getInstance().clear(), 0);
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub https://github.com/ericgio/react-bootstrap-typeahead/issues/211#issuecomment-323404266, or mute the thread https://github.com/notifications/unsubscribe-auth/AAoGaubgMMqSjTK_vIDlGa5-cquf0GjAks5sZcAsgaJpZM4OeqeO.
@ChuckIrvine: As mentioned above, I believe this is a problem with your implementation and not a bug, since I've been able to implement the behavior you describe without any issues. Like I said, though, I can't help you without a repro case.
@ericgio This is feeling like a timing bug. Check out the sample below. Using the plain clear call, the input retains the text (bad). With the setTimeout the input flickers with the text and then clears (good).
import React, { Component } from 'react'
import { Typeahead } from 'react-bootstrap-typeahead'
import 'react-bootstrap-typeahead/css/Typeahead.css';
export default class FilterBar extends Component {
render() {
const onChange = values => {
if (values.length)
setTimeout(() => this.refs.typeahead.getInstance().clear(), 0);
// this.refs.typeahead.getInstance().clear();
}
return (
<Typeahead
ref='typeahead'
onChange={onChange}
options={[{ label: 'one', key: 'one' }, { label: 'two', key: 'two' }]}
/>
)
}
}
Ok I see what's happening. @jeffmcaffer: Thanks for the repro case.
In the uncontrolled case, the onChange callback that triggers the clear happens synchronously, but the text update is handled asynchronously in a state change. The selection is actually cleared correctly, but the input value is overwritten afterwards. Using setTimeout forces the clear call to happen after state has been updated, so the selection and input value are correctly cleared.
The implementation I had used before involved a controlled component and worked fine, since the new props being passed in triggered the correct update.
I see several ways to fix the bug, but I want to make sure I do it in a robust way that doesn't lead to more issues down the line.
@jeffmcaffer, thanks for finally nailing this one down.
Awesome. Not sure this is a controlled/uncontrolled question though. My really code gets the list of options in as a prop. The only reason to use ref here is to get access to the component to call clear. Otherwise the DOM is not used/accessed.
In my case the Typeahead is a fast way to populate a secondary list. The list prop coming into this component does not change, the user just keeps picking more entries. So no props change, no update.
@ericgio one thing to consider is building in the notion of clearing on change. For example, a new prop clearOnChange or some such. That would address at least some of the scenarios and remove the need for ref and infinite loop checking... Of course, there are more scenarios so it is not the full answer.
Not sure this is a controlled/uncontrolled question though
Not for your purposes, but it does matter in terms of the internal implementation. My comment above was mainly for posterity.
one thing to consider is building in the notion of clearing on change
I've been trying to find the right balance between making common functionality available out of the box and providing enough flexibility to let developers account for special cases. So far, clear-on-select has fallen into the latter bucket, but it may be worth rethinking. One thing I'd like to explore is using higher-order components as a middle ground by providing encapsulated functionality for those who need it without bloating the component for those who don't. Clear-on-select might be a good candidate for this approach.
This should be fixed as of v2.3.2. I'm not thrilled with the solution, which relies on the ordering of state updates. I added a test to mitigate the fragility, but I'd eventually like to find a better solution.
This is how it works with me in a functional component hope it help.
import React, { useState, useEffect, useRef } from 'react'
import { Typeahead, withAsync } from 'react-bootstrap-typeahead';
const AsyncTypeahead = withAsync(Typeahead);
function SearchAdmins(props) {
const typeahead = useRef(null);
const onChange = values => {
if (values.length)
typeahead.current.clear()
}
return (
<AsyncTypeahead
id="searchUsers"
ref={typeahead}
onChange={onChange}
useCache={true}
/>
)
}