Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Searching in a list of values (menulist, textbox)

91 views
Skip to first unread message

Michael Hofer

unread,
Jan 26, 2012, 6:35:48 AM1/26/12
to dev-te...@lists.mozilla.org
Hello,

I want the user to be able to search and select a value from a
predefined list. I'm using an editable menulist with a menupopup for
this at the moment:

<menulist id="user" editable="false" sizetopopup="none" flex="1">
<menupopup>
<menuitem label="John Doe" value="1"/>
<menuitem label="John Smith" value="2"/>
<menuitem label="Max Mustermann" value="3"/>
</menupopup>
</menulist>

The label is used for display while the value is returned to the server
as the selected id. This works fine so far. The only problem is with the
search.

Searching (by typing) only works by blindly typing the initial letters
of the name. Also on longer strings you have to be really fast, or
you'll have to start over again (typing timeout).

Making the menulist editable doesn't help either. While the user can
type into the editable menulist in that case, the string is not applied
as a search string (for filtering the list). Also I'd like to have
inter-string-search (typing 'Smith') and ideally visual feedback (like
highlighting search strings in the result list).

An option could be to write a custom autocomplete textbox (like
described on
https://developer.mozilla.org/en/How_to_implement_custom_autocomplete_search_component).
But is it possible do get the ids of the entries into that? How do I get
the id of the 'selected' element?

Isn't there some way to do a custom menulist/menupopup combination for
this (couldn't find documentation on this)?

Thank you very much for your help!

regards,
Michael

Michael Hofer

unread,
Feb 1, 2012, 3:38:02 PM2/1/12
to dev-te...@lists.mozilla.org
Am 26.01.12 12:35, schrieb Michael Hofer:
> I want the user to be able to search and select a value from a
> predefined list. I'm using an editable menulist with a menupopup for
> this at the moment:
[...]
> An option could be to write a custom autocomplete textbox (like
> described on
> https://developer.mozilla.org/en/How_to_implement_custom_autocomplete_search_component).
> But is it possible do get the ids of the entries into that? How do I get
> the id of the 'selected' element?

I played around with the textbox autocomplete a bit. I can use objects
as array-elements (containing the displayValue and the id):

ProviderAutoCompleteResult.prototype.getValueAt = function(index) {
return this.results[index]['id'];
};

ProviderAutoCompleteResult.prototype.getLabelAt = function(index) {
return this.results[index]['displayValue'];
};

This way the labels (displayValue) are displayed as autocomplete
suggestions, but when the user selects an entry the value (id) gets
filled into the textbox.

Not exactly what I want. Any ideas how to access/store the id of the
selected entry for later retrieval (while displaying the displayValue)?
Is there a way to access the textbox from within the
'ProviderAutoCompleteResult' (nsIAutoCompleteResult) to attach something
like a 'selectedId' attribute to it?

Thanks for your help!

regards,
Michael

Michael Hofer

unread,
Feb 6, 2012, 3:54:09 PM2/6/12
to dev-te...@lists.mozilla.org
Am 01.02.12 21:38, schrieb Michael Hofer:
> Am 26.01.12 12:35, schrieb Michael Hofer:
> Not exactly what I want. Any ideas how to access/store the id of the
> selected entry for later retrieval (while displaying the displayValue)?
> Is there a way to access the textbox from within the
> 'ProviderAutoCompleteResult' (nsIAutoCompleteResult) to attach something
> like a 'selectedId' attribute to it?

I'm now trying to use the comment field of the autocomplete textbox for
my id property (accessible via textbox.controller.getCommentAt(index)).

I could call this in an ontextentered-handler attached to the textbox.
But I couldn't find a way to get the index of the selected element. The
'param' passed into the handler (which actually has to be called 'param'
to work) is of type 'KeyboardEvent'.

Any ideas on how to get the selected index?

thanks,
Michael

Michael Hofer

unread,
Feb 7, 2012, 4:57:34 PM2/7/12
to dev-te...@lists.mozilla.org
Am 06.02.12 21:54, schrieb Michael Hofer:
> Am 01.02.12 21:38, schrieb Michael Hofer:
>> Am 26.01.12 12:35, schrieb Michael Hofer:
>> Not exactly what I want. Any ideas how to access/store the id of the
>> selected entry for later retrieval (while displaying the displayValue)?
>> Is there a way to access the textbox from within the
>> 'ProviderAutoCompleteResult' (nsIAutoCompleteResult) to attach something
>> like a 'selectedId' attribute to it?
>
> I'm now trying to use the comment field of the autocomplete textbox for
> my id property (accessible via textbox.controller.getCommentAt(index)).
[...]
> Any ideas on how to get the selected index?

I finally found a way. There is an 'autocomplete-did-enter-text'
notification which can be observed. Because this notification is sent
before the popup closes (as opposed to the ontextentered event), the
index of the selected element is still available in the observer. So the
comment (or other fields) from the chosen entry can be retrieved via

subject.controller.getCommentAt(subject.popup.selectedIndex)

in the observer.

Cost me quite some time to figure that out. Maybe it helps somebody else...

regards,
Michael

Michael Hofer

unread,
Feb 8, 2012, 10:08:20 AM2/8/12
to dev-te...@lists.mozilla.org
Am 07.02.12 22:57, schrieb Michael Hofer:
>>> Not exactly what I want. Any ideas how to access/store the id of the
>>> selected entry for later retrieval (while displaying the displayValue)?
>>> Is there a way to access the textbox from within the
>>> 'ProviderAutoCompleteResult' (nsIAutoCompleteResult) to attach something
>>> like a 'selectedId' attribute to it?
>>
>> I'm now trying to use the comment field of the autocomplete textbox for
>> my id property (accessible via textbox.controller.getCommentAt(index)).
> [...]
>> Any ideas on how to get the selected index?
>
> I finally found a way. There is an 'autocomplete-did-enter-text'
> notification which can be observed. Because this notification is sent
> before the popup closes (as opposed to the ontextentered event), the
> index of the selected element is still available in the observer. So the
> comment (or other fields) from the chosen entry can be retrieved via
>
> subject.controller.getCommentAt(subject.popup.selectedIndex)

Somebody asked me for a code example for this. Here it is:

XUL (Autocomplete Textbox):
--------------------------------------------------------------
<panel id="kunde_popup_autocomplete" type="autocomplete"
noautofocus="true" />
<textbox id="kunde"
type="autocomplete"
autocompletepopup="kunde_popup_autocomplete"
autocompletesearch="json-autocomplete"
completedefaultindex="true" forcecomplete="true"
enablehistory="true"
showcommentcolumn="true"
autocompletesearchparam='[]'"/>

- The separate panel set via the autocompletepopup attribute on the
textbox is not strictly necessary. But without it I got popup display
problems in some places. Place the panel separately from the textbox
(like on the top level of the document) if you've got display problems.

- "json-autocomplete" is my custom autosearch component implemented
basically like described on
https://developer.mozilla.org/en/How_to_implement_custom_autocomplete_search_component#Basic_example_for_Gecko_2.0_and_up_%28Firefox_4_.2F_Thunderbird_3.3_.2F_SeaMonkey_2.1%29

- The autcocompletesearchparam on the textbox is set via script on init
to a string containing json encoded data (with the data key containing
an an array of hashes each having fields for displayValue, comment,
id,...) -> See http://pastebin.com/emg0nzWc for an according
startSearch-implementation (autocompletesearchparam is received as
searchParam there). In that implementation getValueAt(index)
(nsIAutoCompleteResult) would return
this.results[index]['displayValue']
while getCommentAt(index) would return
this.results[index]['comment']
(or ['id'] if you used the comment field for the id)


Observer (for receiving the index of the selected entry)
----------------------------------------------------------

function myObserver()
{
this.register();
}
myObserver.prototype = {
observe: function(subject, topic, data) {
var id = subject.controller.getCommentAt(subject.popup.selectedIndex);
alert( 'id of selected element (read from comment field): ' + id );
},
register: function() {
var observerService =
Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
observerService.addObserver(this, "autocomplete-did-enter-text",
false);
},
unregister: function() {
var observerService =
Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
observerService.removeObserver(this, "autocomplete-did-enter-text");
}
};

var testObserver = new myObserver();

This will be called after autocomplete was at work (but before the popup
closes, so the selectedIndex is still available here). There are more
undocumented notifications like this in
toolkit/components/autocomplete/nsAutoCompleteController.cpp:
'autocomplete-will-enter-text', 'autocomplete-will-revert-text',
'autocomplete-did-revert-text'


Improvements
----------------------------------------------------------------

It's generally a good idea to have the xulrunner or firefox source code
available for reference when working on these less documented features.
Also: Don't mess around too much with internals when you are not in
control of your xulrunner-environment (like when writing plugins).

1) To implement additional fields (like a getIdAt(index)-function in
your nsiAutoCompleteResult) it seems to be necessary to also extend
(implement your own?) nsIAutoCompleteController. Without that, all you
have available from the controller is comment, image, label/value and style.
I didn't do that yet. Code examples anyone?


2) The default panel associated with the autocomplete textbox uses a
tree with two columns (one for the value, one for the comment) for
display. Using a richlistbox gives better formatting options + free
search string highlighting in the result list (similar to awesomebar in
firefox). But

<panel id="kunde_popup_autocomplete" type="autocomplete-richlistbox" />

(as described in the tutorial) doesn't work properly for me (xulrunner
2.0), but

<panel style="-moz-binding:
url(chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup)"
id="kunde_popup_autocomplete" type="autocomplete" noautofocus="true" />

does (You'd better define a corresponding css class for that style).

To modify the structure of the individual richlistitems, you can extend
the XBL:

XBL
----
<binding id="my-autocomplete-richlistitem"
extends="chrome://global/content/bindings/autocomplete.xml#autocomplete-richlistitem">
<content>
<!-- copy/modify the content from
chrome://global/content/bindings/autocomplete.xml#autocomplete-richlistitem
here -->
</content>
</binding>

CSS
---
.autocomplete-richlistitem {
-moz-binding:
url('/path/to/my-autocomplete.xml#my-autocomplete-richlistitem');
}

For modifying the popup (which is creating the
autocomplete-richlistitems) also extend
chrome://global/content/bindings/autocomplete.xml#autocomplete-rich-result-popup.

Hope this helps somebody.

regards,
Michael
0 new messages