Skip to content
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

[Autocomplete] Warn wrong comparison getOptionSelected implementation #19595

Closed
tagaychinova opened this issue Feb 6, 2020 · 22 comments · Fixed by #19699
Closed

[Autocomplete] Warn wrong comparison getOptionSelected implementation #19595

tagaychinova opened this issue Feb 6, 2020 · 22 comments · Fixed by #19699
Labels
component: autocomplete This is the name of the generic UI component, not the React module! docs Improvements or additions to the documentation good first issue Great for first contributions. Enable to learn the contribution process.

Comments

@tagaychinova
Copy link

Bug Demo: https://codesandbox.io/s/material-demo-q3fno

autocomplete

@oliviertassinari oliviertassinari added the duplicate This issue or pull request already exists label Feb 6, 2020
@oliviertassinari

This comment has been minimized.

@oliviertassinari oliviertassinari added component: autocomplete This is the name of the generic UI component, not the React module! and removed duplicate This issue or pull request already exists labels Feb 6, 2020
@oliviertassinari
Copy link
Member

@tagaychinova Interesting case, I propose the following new error message:

diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
index dfd6171c8..47e2a4c59 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
@@ -439,6 +439,24 @@ export default function useAutocomplete(props) {
       const item = newValue;
       newValue = Array.isArray(value) ? [...value] : [];

+      if (process.env.NODE_ENV !== 'production') {
+        let matches = 0;
+        for (let i = 0; i < newValue.length; i += 1) {
+          if (getOptionSelected(item, newValue[i])) {
+            matches += 1;
+          }
+        }
+
+        if (matches > 1) {
+          console.error(
+            [
+              'Material-UI: the `getOptionSelected` method of useAutocomplete do not handle the arguments correctly.',
+              `The component expects a single value to match a given option but found ${matches}.`,
+            ].join('\n'),
+          );
+        }
+      }
+
       const itemIndex = findIndex(newValue, valueItem => getOptionSelected(item, valueItem));

       if (itemIndex === -1) {

@oliviertassinari oliviertassinari added good first issue Great for first contributions. Enable to learn the contribution process. docs Improvements or additions to the documentation labels Feb 6, 2020
@ahmad-reza619
Copy link
Contributor

@oliviertassinari why not we try to solve this issue instead of giving error message?

@oliviertassinari
Copy link
Member

oliviertassinari commented Feb 7, 2020

@ahmad-reza619 This error message is a lead/tip on how to solve the problem in your codebase. If you can't figure it out with it, then this warning might not be good enough. I wonder what lead to this wrong usage of the API and how we could better help 🤔.

@oliviertassinari oliviertassinari changed the title [Autocomplete]: onChange works incorrectly when disableCloseOnSelect is true [Autocomplete] Warn wrong comparison getOptionSelected implementation Feb 7, 2020
@oliviertassinari
Copy link
Member

Maybe we should rename getOptionSelected to optionEqualValue or something similar 🤔.

@ahmad-reza619
Copy link
Contributor

Maybe we should rename getOptionSelected to optionEqualValue or something similar 🤔.

sounds good, and btw why not replace the for with Array.prototype.some for edgy fp style 😎

@ahmad-reza619
Copy link
Contributor

ahmad-reza619 commented Feb 7, 2020

something like this

const matches = newValue.some(val => optionEqualValue(item, val));

if (matches) {
   console.error(
        [
            'Material-UI: the `getOptionSelected` method of useAutocomplete do not handle the arguments correctly.',
            `The component expects a single value to match a given option but found ${matches}.`,
        ].join('\n')
   )
}

@eps1lon
Copy link
Member

eps1lon commented Feb 7, 2020

console.error

I'd prefer a warning here and I'm not even sure there aren't valid use cases for this e.g. fallbacks.

And I'm not sure why this should warn. What is wrong with the provided codesandbox? It seems like a bug on our side to me.

@oliviertassinari
Copy link
Member

oliviertassinari commented Feb 7, 2020

@ahmad-reza619 What about IE 11?
@eps1lon makes me think of a previous discussion we didn't resolve. When should we use error vs warn?

Ok, here is the solution. The getOptionSelected method accepts two arguments. A value and an option. Its purpose is to signal when two objects from these ensembles are identical. We use it to construct a function that takes an option and maps it to the corresponding value. You can't say option A points to all the values.

@eps1lon
Copy link
Member

eps1lon commented Feb 7, 2020

You can't say option A points to all the values.

How does this apply here? Each option and current value is unique in the codesandbox.

Ok, here is the solution. The getOptionSelected method accepts two arguments.

Tried that in the codesandbox. The second parameter is undefined.

@oliviertassinari
Copy link
Member

I hope it will be clearer with https://codesandbox.io/s/material-demo-b3nsz.

-getOptionSelected={option => value.find(v => v.id === option.id)}
+getOptionSelected={(option, value) => value.id === option.id}

@ahmad-reza619
Copy link
Contributor

ahmad-reza619 commented Feb 7, 2020

@oliviertassinari Ok sorry for misunderstanding, but looks like Array.prototype.some is actually supported in IE based on this MDN article.

But well yeah it only return true if there is one of its predicate is true 🤔

@ahmad-reza619
Copy link
Contributor

Can i give it a go?

@oliviertassinari
Copy link
Member

Perfect for IE 11 :) but I think that it could be interesting display the number of matches.

@oliviertassinari
Copy link
Member

Honestly, I'm not sure the warning will be enough. It took me a good chunk of time to figure out what was wrong with your example. Considering I have myself designed most of the component, I can only imagine how it can be confusing for somebody else.
@eps1lon what do you think about changing the name of the prop?

@scrozier
Copy link

scrozier commented Apr 27, 2020

FWIW, I would favor (also) renaming the prop, as you suggested, @oliviertassinari. It specifically does not do what it name implies. I have to rethink it every time I come back to it.

BTW, I love this component. :-)

@oliviertassinari
Copy link
Member

@scrozier What name you would suggest?

@scrozier
Copy link

@oliviertassinari It's tricky, isn't it? I wonder if that means that there's an underlying architectural issue? You're really wanting to find out which option is selected, ergo getOptionSelected, but this particular prop does not do that, it's just a supporting player. optionEqualValue seems pretty good, if not exactly elegant. Other thoughts: optionEquivalence, optionMatch, optionMatcher, optionFinder, optionByValue. I don't think I know the body of work well enough to know what fits with the semantic direction. I think I land on optionByValue or your original optionEqualValue, without a strong opinion either way.

BTW, thank you for your shepherding of this excellent project. You do a great job.

@oliviertassinari
Copy link
Member

@scrozier Both options sound great.

@scrozier
Copy link

@oliviertassinari Should I open an issue for this?

@oliviertassinari
Copy link
Member

@scrozier Sure, if you want to submit a pull request directly, that will do it too :)

@scrozier
Copy link

@oliviertassinari I shall give it a whirl....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: autocomplete This is the name of the generic UI component, not the React module! docs Improvements or additions to the documentation good first issue Great for first contributions. Enable to learn the contribution process.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants