-
Notifications
You must be signed in to change notification settings - Fork 150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix custom templates issue with defaultValue #425
base: main
Are you sure you want to change the base?
Conversation
I've encountered this issue as well - is there anything I could help with to get this merged? |
@danielnaab not sure there is. Have you seen #430? It says they'll prioritize UK public sector (which includes me) so hoping it can go out as part of #433 but I haven't heard anything |
Hi @ediblecode, We've been looking at this to try and review it for you, but are struggling to get our head around what the correct behaviour should be without a more realistic example. Can you talk us through your use case and what you expect to happen? When would you set a Thanks! |
Thanks for getting back to me @36degrees. We're using it for a site search typeahead (rather than a list of finite options for a form). The suggestions are requested from a server API endpoint using a function passed to the This is how we're using it if it helps: https://github.com/nice-digital/global-nav/blob/master/src/Header/Search/Autocomplete/Autocomplete.jsx#L123. Hopefully that, in tandem with the codepen in the issue I raised might be a bit clearer but if not let me know and I'll try add some more details. Thanks |
Ah, OK, so then when you display the search results page you're using I appreciate at the same time that the current behaviour (displaying The expected behaviour here seems a little undefined – what should happen when you focus the input? Given we're in a search context, I think I'd expect the search to be run again and to see the same results that I saw before I submitted the page, not an empty list. I'll review the code as it stands at the moment with this in mind, and let's see where we get to. |
@@ -93,7 +96,7 @@ export default class Autocomplete extends Component { | |||
} | |||
|
|||
isQueryAnOption (query, options) { | |||
return options.map(entry => this.templateInputValue(entry).toLowerCase()).indexOf(query.toLowerCase()) !== -1 | |||
return options.some(entry => (this.templateInputValue(entry) || '').toLowerCase() === query.toLowerCase()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just want to check that I'm reading this correctly – this function is effectively doing the same thing as before, it's just using slightly neater syntax and allowing for this.templateInputValue(entry)
to return false
without trying to treat false
as a string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, except that:
allowing for
this.templateInputValue(entry)
to returnfalse
is more broadly "this.templateInputValue(entry)
to return something falsey" - and this is the key, it allows us to return undefined from templates.inputValue
:
templates: {
inputValue: function(suggestion) {
return suggestion && suggestion.Title;
}
}
which you have to do if you're providing an inputValue
function, because it is called when the plugin loads, so not handling an undefined
suggestion
argument would result in an Exception.
@@ -58,12 +58,15 @@ export default class Autocomplete extends Component { | |||
constructor (props) { | |||
super(props) | |||
|
|||
const { defaultValue } = props | |||
const isQueryAnOption = defaultValue.length > 0 ? this.isQueryAnOption(defaultValue, [defaultValue]) : false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem quite right to me, because we're passing a known value and an array containing exactly that known value to a function that's meant to test whether the value is in the array. What we really seem to be testing here is whether this.templateInputValue
returns a value that matches or not, so should we just be calling that directly?
I'm not sure isQueryAnOption
really describes what's actually going on here either. Is there a better way to describe this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we're passing a known value and an array containing exactly that known value to a function that's meant to test whether the value is in the array
we are, but we want to use the value returned from templateInputValue
as you rightly point:
What we really seem to be testing here is whether this.templateInputValue returns a value that matches or not, so should we just be calling that directly?
Fair point, the condition would then become something like this, which is definitely much simpler:
const isQueryAnOption = this.templateInputValue(defaultValue).toLowerCase() === defaultValue;
I think I was trying to re-use the existing isQueryAnOption
function as it was already doing what we want.
I'm not sure
isQueryAnOption
really describes what's actually going on here either.
I guess the behaviour here is whether we should show the default value as an option on focus. So maybe, showDefaultValueAsOption
or something? The state initialisation would then become:
options: showDefaultValueAsOption? [defaultValue] : [],
which seems to make sense!
@@ -300,6 +300,39 @@ describe('Autocomplete', () => { | |||
expect(autocomplete.state.options[0]).to.equal('France') | |||
expect(autocomplete.state.query).to.equal('France') | |||
}) | |||
|
|||
it('is prefilled with a simple custom inputValue template', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to write these tests that makes it more explicit what's going on?
They currently feel like they're relying on a side effect of the way the inputValue
template is implemented in each one, and whether it's dealing with a string or an object. It's not clear to me how the difference is described by the test description, or why the different functions should give different results.
I think having reviewed your proposed changes again there's something odd about the fact that we're relying (I think?) on the The fact that |
Thanks for the review, I'll have a look at the specific feedback. And to answer some other points:
yes, that's right.
yup, fair enough. Do you think this legit within scope? It feels to me, that because
Very, very good point. I think you're right actually that the expected behaviour should maybe be to display suggestions for the term on focus, and that is new feature I think, specific to site search - I can't see a way to get suggestions to appear on focus based on the current options. Showing suggestions for search on focus is certainly a common paradigm for search engines. I understand that is different to the current behaviour within accessible-autocomplete though, so would be a new feature. Maybe an option of So in light of that, I think the expected behaviour would be for it to show no options on focus. I can't see any other way round that? Unless we change the behaviour so the focus doesn't just show |
In #424 you suggested another approach:
Did you explore this at all? Effectively, I think we'd instead be trying to solve a slightly simpler bug:
This would then allow you to address this in your own |
Interesting, so I did. And I even suggested option 2 was better didn't I?! Thanks, past me. I'll look at that then, might be more elegant. I'm sure there was a reason why I went down the other route, but pushing the logic to the consumer as to what they return from the function makes sense if that works. |
6c88d92
to
4b55ff3
Compare
Hey @ediblecode, long time no see (took a little squinting at your profile photo!) We've given this PR a milestone and I've rebased it with |
Fixes #424