-
Notifications
You must be signed in to change notification settings - Fork 610
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
Various list data formats and separate title/value #16851
Various list data formats and separate title/value #16851
Conversation
New "data" configuration property is function, which is called for each initial list item in any format to convert it to object like this one: { title: "United States", value: "US" } This object is then used everywhere in API. So instead of item text filter(), sort(), item() and replace() functions now get an object with separate "title" and "value" properties. Despite this data format change, old code will continue to work as before. This is what Suggestion() shim is for. It uses "title" property when string is expected everywhere in the API. The only change is that now we have "value" property and it would be used in default implementation of replace() method directly, so now suggestion title you see in completer and the value inserted to the input when the item is selected can be independent.
This is a next step for #16821 and whole key/value story. New
While already useful, I believe it can be improved. Lot's of PRs and issues are about support for key/value objects and arrays. With this PR you need to provide We can try to separate these 2 Default data conversions will still work in that case, even if we change |
Example 1. List of objects. All you need is to provide a custom new Awesomplete(urlInput, {
data: function(item, input) {
return { title: item.name, value: item.url };
},
list: [
{
"name": "Awesomplete",
"url": "https://leaverou.github.io/awesomplete/"
},
{
"name": "Bliss",
"url": "https://blissfuljs.com"
},
{
"name": "Stretchy",
"url": "https://leaverou.github.io/stretchy/"
},
{
"name": "chainvas",
"url": "https://leaverou.github.com/chainvas"
}
]
}); You'll see name of project in the completer and once selected, the URL of the project would be inserted into input. Of course you can just use data: function(item, input) { return item } |
Example 2. List of arrays. All you need is to provide a custom new Awesomplete(countryCodeInput, {
data: function(item, input) {
return { title: item[0], value: item[1] };
},
list: [
[ "Belarus", "BY" ],
[ "China", "CN" ],
[ "United States", "US" ],
]
}); You'll see full name of the country in the completer and once selected, the country 2 letters code would be inserted into input. |
Thanks for working on this!!
Some concerns, after briefly skimming this (so I might have missed something):
|
1 - Yes, getting key/value from HTML is one of requested features. To keep this PR minimal I didn't tried to implement it, but it would be trivial, once we decide to go with this one I guess. 2 - The initial list in Can you elaborate on this please:
I think storing The |
Yes, I totally didn't expect this PR to deal with the HTML API, just wanted to raise this concern early on. About the second point, I mean that examples like these should still work: var input = document.getElementById("myinput");
new Awesomplete(input, {
list: ["Ada", "Java", "JavaScript", "Brainfuck", "LOLCODE", "Node.js", "Ruby on Rails"]
}); var input = document.getElementById("myinput");
var awesomplete = new Awesomplete(input);
/* ...more code... */
awesomplete.list = ["Ada", "Java", "JavaScript", "Brainfuck", "LOLCODE", "Node.js", "Ruby on Rails"]; Not just for legacy reasons, but because in these cases, it would be a huge hassle to repeat the text twice because you want to use the same text as a key and a value. |
Lea, Example 1 and Example 2 are here just to show what else became possible if this PR is merged. It's the base for requested feature of using key/value or array for item data. To support this by default we can add just a little bit on top. The default case with strings just works. It's the beauty with this PR. No breaking changes. At least I can't find one and all tests are passing. No code changed in filter(), sort() and item() methods which now work with |
I see. Cool!
Why not just delete it? |
d79b645
to
8d6d07b
Compare
Deleted. I often use source as a doc and there are no JSDocs, so having commented out argument makes it obvious, that there is in fact a second argument you can use in your implementation. |
One more thing. I wonder if |
Oh, I hadn't realized it's actually called with that argument, I thought it was just leftover. If it's an optional argument then don't remove it! Either include it as a normal argument (what I usually do) or commented out. Sorry! Not sure about |
4df2524
to
7dbe4b5
Compare
Added deleted argument back. Looks like everything is settled, so I also changed name of argument from The original item from |
I'll look into other popular completers to see what name they use. |
This PR is becoming a little big. Maybe I should open a separate PR for default data converters explained in my comment above #16851 (comment) |
The size of this PR is ok. |
Email example was originally tricky. It needs to be changed, because In this PR the So only this example should be changed. It's a breaking change for this particular case, but I think it's a good one. We now get data from array of suggestions, not from DOM. There were requests to make it possible to display one data and insert another in completer. Like add prefix to each item in completer but still insert data from original list. This becomes possible even with old API. Suggestions are prepared with Also, changed example is now simpler. It only needs the data generation part, which is now separate from LI item construction in
If you mean the removal of @ sign in original list, I can revert that. It's just that we don't need them anymore in the original list. |
I looked into some popular autocompleters. jQuery UI autocomplete widget and some others are using https://html.spec.whatwg.org/multipage/forms.html#the-datalist-element
https://html.spec.whatwg.org/multipage/forms.html#concept-option-label
So I think we should also go with |
Totally agree! External consistency with other APIs is always good. :) |
In case you missed it - I've already changed title -> label :) And what about your concern with email example change answered by me in this comment? |
Ah sorry, I had missed it. |
The If we need to change like you described, then this public method kind of loses it's purpose. Why have data conversion method, if we can't rely on it to provide required object? The I think data conversion methods should be probably public, to be able to override them for default String/Array/Object/... if we support them out of the box. Or we can make default cases unchangeable and provide additional method to plug in data conversion for whatever item format we don't support out off the box. And again, it would take data in some format and provide guaranteed We can have separate So we still have this object either in data conversion method or data changer method. Unless we make data conversion private and non extendable. I can try to address your concern, but that would be a lot of changes to support defaults for String/Object/Array and initialization from HTML. This may become even harder to agree on. |
To make If we split type conversion and data generation methods (which I think we should do anyway)...
So we convert data twice and wrap it with Suggestion twice. I feel like we are trying to optimize to much for the minor use case (dynamic data generation like in email example). Data conversion can just work by default and not require custom data method anyway. |
Possible way to remove content duplication (please also my comments above): bb9ce87 To me it looks like too much hassle just to optimize for this minor use case. We convert items twice, we wrap with Suggestion twice. Of course, we can make What do you think? |
.filter(function(item) { | ||
return me.filter(item, value); | ||
.map(function(item) { | ||
var suggestion = new Suggestion(convert(item)); |
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 only need to wrap with Suggestion
here for old string based API inside data
method.
I see. No, this new private Idea (might be a bad one, I’m just brainstorming here): What if the output of Again, sorry for being a prick here, I imagine it must be pretty frustrating to put time and effort on stuff and have it take ages to be merged. I'm just trying to do what's best for the project, which is not always obvious (even to me) and often only emerges in discussion. |
We need something for data conversion. I suggested initially to split data conversion / data generation. Doesn't matter if it's a method or part of Suggestion class constructor. But if it's a private thing, we can't change it. That's the problem.
No worries. Maybe it's even easier to discuss when you at least see the code. I agree, that having the same API everywhere with
No worries Lea, I just feeling like maybe I'm out of ideas to support all your cases in a reasonable way. I'll try to explain.
We have almost the same code now with var data = me.data(suggestion, value);
return new Suggestion(convert(data)); If I understood you correctly, the only change would be that we move current
With my latest commit this already works.
Why do we need to expose it? Isn't it better if it's hidden and users of API don't care and don't even know we have some wrapper at all? I've planed to split and expose a data conversion logic itself as public API in next PR if this PR merged. One of my sketches was something like: _.CONVERT = {
// for Strings and as a default case
String: function(data) {
return { label: data, value: data };
},
Object: function(data) {
return data;
},
Array: function(data) {
return { label: data[0], value: data[1] };
}
};
// then, given that item is initial item from list in whatever data format
var convert = _.CONVERT[Array.isArray(item) ? "Array" : typeof item === "object" ? "Object" : "String"];
// and then just call
convert(item);
// to support new data format like Date we can then just add:
Awesomplete.CONVERT.Date = function(data) {
return { label: data.toString(), value: data.valueOf() };
} Then the original |
The thing that adds inelegance is the fact that So since we need same API we have to convert data to And if this custom |
BTW, since we need to support the The good news is it's not a lot of code to add this support. Maybe we need to deal with the whole data conversion before, but maybe we can add it too, since it already tells that it's better to move the first data conversion to list setter. |
I think we should keep the Thoughts? |
Yes, it allows elegant short functions for filter, replace etc. even now when we don't expose it. Do you mean the user of API will provide
I'll remove |
.filter(function(item) { | ||
return me.filter(item, value); | ||
.map(function(suggestion) { | ||
return convert(me.data(suggestion, value)); |
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.
No more ugly things like new Suggestion(convert(foo)) :)
One more idea. We can make Our default conversion will handle Array/String/Object cases, so So |
Lea, can you please read the recent email notifications for this PR? I tried to make more readable comments about 2 latest commits and lost the big one 😠. The comment about the last commit where First commit vlazar@fb48e7c |
Last idea as a separate and as minimal as possible PR #16852 |
I’m a bit confused with all the comments and PRs so I might have missed something. Why do we still need a convert method? I thought we would just put it in the If you're not still using a |
First commit - with convert method it was cleaner to wrap in multiple places with both Second commit - I've moved data conversion to Suggestion constructor as you suggested. Finally, I've created a separate PR #16852 where I don't use multiple wrapping at all. Do you like it that way? The I haven't changed the argument names yet for PR to be easier to review. And the Object case in Suggestion constructor should be more specific, since we are looking for Object with label/value keys, otherwise we should skip to the most generic String case. |
Closing in favor of #16866 |
New
data
configuration property is function, which is called for each initial list item in any format to convert it to object like this one:This object is then used everywhere in API. So instead of item text
filter()
,sort()
,item()
andreplace()
functions now get an object with separatetitle
andvalue
properties.Despite this data format change, old code will continue to work as before. This is what
Suggestion()
shim takes care of. It usestitle
property when string is expected everywhere in the API.The only change is that now we have
value
property and it would be used in default implementation ofreplace()
method. Suggestion title you see in the completer and the value inserted to the input, when the item is selected can now be fully independent.