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

Capability to differentiate value from displayed text #593

Closed
ThomasG77 opened this issue Feb 23, 2015 · 18 comments
Closed

Capability to differentiate value from displayed text #593

ThomasG77 opened this issue Feb 23, 2015 · 18 comments
Milestone

Comments

@ThomasG77
Copy link

Your library is cool but maybe due to the habit of <select><option> couple for sending identifier, I would like to use a value that differs from the text when event 'awesomplete-selectcomplete' is fired.
Another reason could be the fact, that I want to avoid encoding issue. With accents (I'm French), I don't want to bother about encoding client/server when sending info (although nowadays, everyone use UTF-8, in my dreams...) so an identifier is better IMO.

I don't know if it's a design choice but I didn't see any ways to achieve it.
To try to bypass the lib behaviour cleanly, I created the following example below

<input id="myinput" list="mylist" />
<datalist id="mylist">
    <option value="a">Ada</option>
    <option value="b">Java</option>
    <option value="c">JavaScript</option>
    <option value="d">Brainfuck</option>
    <option value="e">LOLCODE</option>
    <option value="f">Node.js</option>
    <option value="g">Ruby on Rails</option>
</datalist>

<script>
document.querySelector('#myinput').addEventListener('awesomplete-selectcomplete', function(evt){
  console.log(this.value);
})
</script>

Unfortunately, it echoed Python but never a when choosing the first option.

I could always do the below really dirty solution but I would prefer to avoid it.

What is the way to go for my requirements if any?
Thanks for your input.

document.querySelector('#myinput').addEventListener('awesomplete-selectcomplete', function(evt) {
  var lib = this.value;
  var val = Array.prototype.slice.call(document.querySelectorAll('#mylist option')).filter(function(option) {
    if (option.text == lib) {
      return true;
    };
    return false;
  })[0].value;
  console.log(lib, val);
});
@DanyUP
Copy link

DanyUP commented Feb 23, 2015

👍
I had the same problem when trying to implement the select box functionality... I resolved using your "dirty" solution, but I wonder if there could be a better way.

Can we save option values inside list array?

@LeaVerou
Copy link
Owner

Yes, there definitely should there be a better way. At the very least, we should utilize the label property in option, when the list is specified via a <datalist>.

@kohenkatz
Copy link

👍 I would really like to be able to do this too.

@ThomasG77
Copy link
Author

For label advice, it seems support with both label and value is inconsistent between browsers e.g this demo with result between browsers like below http://www.alsacreations.com/xmedia/doc/full/datalist-rendu.png
Although above link to screenshot was done with older browsers, differences remain (tried with FF, Chrome and Opera).

@LeaVerou
Copy link
Owner

LeaVerou commented Mar 4, 2015

So, when the user selects the autocomplete suggestion, does the displayed text get filled in or the value?
If it’s the latter, it’s super easy to implement. If it’s the former, I have no idea how to implement this with inputs…

@psaikali
Copy link

psaikali commented Mar 4, 2015

Hi there,

👍 for this one, I'm having the same problem. I have a URL in a 'data-link' attribute (ie http://img.saika.li/a3EG) and needs to catch this attribute when an is selected.

Unfortunately, the event only returns the input with :
$('.searchform .s').on('awesomplete-highlight', function(e){ console.log(e); });

I really hope that'll be implemented one day !

Anyway, big thanks for the plugin :)

@LeaVerou
Copy link
Owner

LeaVerou commented Mar 4, 2015

@psaikali I have no idea what you just said. I don’t understand, are you answering my question above? If so, what's the answer? And what do you mean with the event? What should be implemented one day?
Lather, rinse, repeat please.

@psaikali
Copy link

psaikali commented Mar 5, 2015

Sorry @LeaVerou. I was just saying "+1" to support the need for this feature ;)

Just used the same trick as +ThomasG77 above.

    var $searchform = $('#header .searchform .s');
    var $searchdatalist = $('#header .searchform datalist option');

    $searchform.on('awesomplete-selectcomplete', function(e){
        var input_value = $(this).val();

        var selected_el = $searchdatalist.filter(function(){
            return $(this).text() == input_value;
        });

        var selected_val = selected_el.length ? selected_el.val() : false;

        if (selected_val) location.href = selected_val;
    });

@pixeline
Copy link

Same here: out of habits of writing selectelements, i created my datalist populating option with value attributes. It would be nice to be able to send the option attribute "value" instead of the option node text.
A possible line of action could be using a hidden input field that would be appended to the form?
I'm in a tight deadline right now so I won't do it, I've switched to a select box for now.

@matanox
Copy link

matanox commented Jul 27, 2015

A change suggestion that solves this, while making the library even more well rounded:

I took a different approach, but it got to a dead end which I think can be easily relieved with a change to the library. My approach does not imply using hidden attributes or such. I override item, filter, and sort like follows below, thus essentially handling a data object argument rather than text.

That works for all mentioned hook functions.

  var inputBar = document.getElementById('inputBar')
  new Awesomplete(inputBar, {
    minChars: 1,
    maxItems: 100,
    list: nodes,
    item: function (node, input) { 
            let suggestedElem = document.createElement('li')
            suggestedElem.appendChild(document.createTextNode(node.data.kind + ' ' + node.data.name + ' ' + '(' + node.id + ')'))
            return suggestedElem
          },
    filter: function (node, input) {
              return node.data.name.toLowerCase().indexOf(input.toLowerCase()) > -1 
            },
    sort: function compare(a, b) {
            if (a.data.name < b.data.name) return -1
            if (a.data.name > b.data.name) return 1
            return 0
          },
    replace: function(node) {
      fireGraphDisplay(node.id) // fails.... because node is the text here, unlike with the other hook functions
      this.input.value = node.data.name // same....
    }
  })

But it only fails with replace which operates "too low" in passing around the display text rather than the data object. I think this can be changed to passing an object to replace rather than the result of item, which may seem to be how it works now (admittedly, haven't examined the source code). If that change is made, then one would be able to work with the component with greater abstraction, while also allowing to do what the initial poster described, in a clean manner.

Is this an api change? I think (?!!) all existing user code that assumes the argument to be a string, should still work.

Forgot to mention, I second this is a great library!

Maybe this suggestion just plugs a hole in the otherwise quite perfect customization api. What do you think?

@lamtranweb
Copy link

I came up with a similar solution:

my-file.js

    // sample data
    var targetCountryInput = document.getElementById('target-country-input');
    var countryNames = [{iso: "AFG",name: "Afghanistan"},{iso: "AGO", name: "Angola"}];
    new Awesomplete(targetCountryInput, {
        list: countryNames,
        autoFirst: true,
        filter : function(text, input) {
            return Awesomplete.FILTER_CONTAINS(text.name, input);
        },
        item: function (text, input) {
            return Awesomplete.$.create("li", {
                innerHTML: text.name.replace(RegExp(Awesomplete.$.regExpEscape(input.trim()), "gi"), "<mark>$&</mark>"),
                "data-iso": text.iso, // encode my custom field into the generated LI
                "aria-selected": "false"
            });
        }
    });

Two things happened here:

Override filter to return the name field of your data

filter : function(text, input) {
            return Awesomplete.FILTER_CONTAINS(text.name, input);
        }

In item override, encode the desired field you want into the generated LI as a "data-*" attribute. In this case, I did:

"data-iso": text.iso, // encode my custom field into the generated LI

This gets you to where @matanster got in the post above.

At this point, you do have to modify Awesomplete's select method, like so:

awesomplete.js

select: function (selected) {
        selected = selected || this.ul.children[this.index];

        if (selected) {
            var prevented;

            $.fire(this.input, "awesomplete-select", {
                text: selected.textContent,
                preventDefault: function () {
                    prevented = true;
                }
            });

            if (!prevented) {
                this.replace(selected.textContent);
                this.close();
                $.fire(this.input, "awesomplete-selectcomplete", selected.dataset);  // add new selected.dataset parameter
            }
        }
    },

The update happens on line 208:

$.fire(this.input, "awesomplete-selectcomplete", selected.dataset);  // add new selected.dataset parameter

This simply passes the dataset object along to the awesomplete-selectcomplete event. Since it's an addition to the code (and using what's already supported by $.fire no less), it would not break anything else.

Then back in my-file.js, do this:

targetCountryInput.addEventListener('awesomplete-selectcomplete',function(e) {
    var selectedCountryName = e.target.value;
    var iso = e['iso']; // got my iso back.
});

@matanox
Copy link

matanox commented Oct 13, 2015

Thanks, will take this into consideration next time around.

@techdragon
Copy link

it would be nice if it just worked with things correctly.
Awesomeplete currently uses the content of the option element, instead of its value, the w3c spec only actually specifies the value. Nothing about the text content of the option element/tag.
https://www.w3.org/wiki/HTML/Elements/datalist
If everything worked "correctly", the content of the value would be submitted by my forms, but it instead of the value attribute, Awesomeplete sends the text content of the option tag.

If my data list looks like

<datalist id="list__employer">
<option value="1">Effertz, Roberts and Feest</option>
<option value="2">Rath and Sons</option>
<option value="3">Altenwerth-Nikolaus</option>
<option value="4">Wiegand-Tromp</option>
<option value="5">Wunsch-Aufderhar</option>
<option value="6">Conn PLC</option>
<option value="7">Mante-Schinner</option>
<option value="8">Altenwerth, Stroman and Kessler</option>
<option value="9">Batz, Baumbach and Konopelski</option>
<option value="10">Kassulke-Casper</option>
</datalist>

The W3C spec says the form should be using "1", "2", "3", "4" etc. But awesomeplete seems to flips this around and actually ignores the value that the spec says should be used.

Could we just get it fixed so that "form submission" uses the value like the spec wants, and awesomeplete uses the text value like it currently does? Something like #16793

@LeaVerou
Copy link
Owner

Agree that if the user provides a select menu or datalist with different values and labels, awesomplete should take advantage of that.

@vlazar vlazar added this to the v1.1 milestone Jan 31, 2016
@nixprosoft
Copy link

Tell me please, when you planing the commit?

@vlazar
Copy link
Collaborator

vlazar commented Feb 11, 2016

@nixprosoft There is an opened PR and ongoing discussion with @LeaVerou on it. Once this PR is merged, there will be support for having value different from displayed text.

After that I plan adding support for initialization from <datalist>.

@vlazar
Copy link
Collaborator

vlazar commented Feb 15, 2016

To everyone interested in differentiating value from displayed text, aka key/value feature, aka array of objects feature.

The code is ready and it's almost 100% backward compatible. To ensure everything working fine for you we need your help with testing it in the wild before it's released. See this PR: Separate label/value for each suggestion in list

@vlazar
Copy link
Collaborator

vlazar commented Mar 12, 2016

Separate label/value is landed #16866
It is also possible to initialize list with separate label/value via <datalist> or <ul>.

Read about different label and value at the end of Basic usage section and about new data method at the end of Extend section.

@vlazar vlazar closed this as completed Mar 12, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests