-
-
Notifications
You must be signed in to change notification settings - Fork 78.8k
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
Alter typeahead to accept synchronous/asynchronous data source #3682
Conversation
Alter typeahead to accept synchronous/asynchronous data source
this is beautiful - thanks! |
could you explain how handleing objects works?
In my case:
So what I want to do is have a "Find song" input with typeahead helper. .1) i want typeahead matcher to look for query in string (artist.name + ' - ' + song.title) Example nr 1: query "ri" should match:
Example nr 2: query "ana - End" should match:
.2) i want typeahead to display helper as string:
Where releaseDate is in format YYYY. Example nr 1: for query "ri" matches should display:
.3) i want input value (submitted in form) to be Artist.name - Song.title {Song.id}" and some callback function to update hidden field value (set it to Song.id) Example nr 1: for query "ri" Given results like in example nr 1
When user clicks / chooses one of results
Then typeahead input value should be set to "Artist.name - Song.title {Song.id}"
And some callback function should be fired, that sets hidden inputs value to Song.id (only the hidden input will be submitted with the form) Conclusion:I am useing typeahead.js from branch 2.1.0-wip (downloaded on 06-07-2012, yesterday) and unfortunately I am getting errors becouse I do not understand exacly what purpose have these options/functions:
And how exacly your code example helps with handleing objects. @mlmorg @fat Could you please explain? Cheers |
I am using this update at the moment. in your case @loostro you need to do something like below.
|
Ok it seems I found the answer to why I got errors: in my application I forgot to serialize objects before returning them as JSON response to the script. I got it working: var labels, mapped;
$("#artist").typeahead({
source: function (query, process) {
$.post('{{ path('radiowww_test_lookup') }}', { q: query, limit: 8 }, function(data) {
labels = [];
mapped = {};
// example response data:
// [
// {
// "id":3,
// "title":"Shoot To Thrill",
// "track_no":1,
// "album": {
// "id":3,
// "name":"Iron Man 2",
// "released_at":"2010-04-19T00:00:00+0200",
// "artist": {
// "id":2,
// "name":"AC\/DC"
// }
// }
// },
// { ..another song object ..},
// {.. another song object ..},
// {.. another song object ..}
// ]
$.each(data, function (i, item) {
// each item is a Song object
var query_label = item.album.artist.name + ' - ' + item.title;
// example query_label: "AC/DC - Shoot To Thrill"
// mapping item object
mapped[query_label] = item;
labels.push(query_label);
});
process(labels);
}, 'json')
},
// Method fired when a result is selected.
updater: function (query_label) {
var item = mapped[query_label];
var input_label = query_label + '{'+ item.id + '}';
// Gonna do some js to save value to hidden input here...
return input_label;
},
}); But I still don't know how to change what is displayed in the popup menu. I'd like it to be Artist.name - Song.Title (Album.name, Album.releaseYear). I'm confused, becouse there are no comments in typeahead.js code, and I'm not sure which function i need to use for that. @gcoop: thanks for help! |
Owkay, I figured it out =) Thanks @gcoop for help!The final version of my code is: var labels, mapped;
$("#artist").typeahead({
source: function (query, process) {
$.post('{{ path('radiowww_test_lookup') }}', { q: query, limit: 4 }, function(data) {
labels = [];
mapped = {};
// example response data:
// [
// {
// "id":3,
// "title":"Shoot To Thrill",
// "track_no":1,
// "album": {
// "id":3,
// "name":"Iron Man 2",
// "released_at":"2010-04-19T00:00:00+0200",
// "artist": {
// "id":2,
// "name":"AC\/DC"
// }
// }
// },
// { ..another song object ..},
// {.. another song object ..},
// {.. another song object ..}
// ]
$.each(data, function (i, song) {
var query_label = song.album.artist.name + ' - ' + song.title;
// example query_label: "AC/DC - Shoot To Thrill"
// mapping song object
mapped[query_label] = song;
labels.push(query_label);
});
process(labels);
}, 'json')
},
// Method fired when a result is selected.
updater: function (query_label) {
var song = mapped[query_label];
// Here gonna add some js to save song id to hidden input
// ...
// If user selects an item, the inputed value will be for example "AC/DC - Shoot To Thrill {3}"
var input_label = query_label + '{'+ song.id + '}';
return input_label;
},
// Method responsible for element view
highlighter: function (query_label) {
var song = mapped[query_label];
var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
var highlighted_label = query_label.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
return '<strong>' + match + '</strong>'
});
// Item will be viewed as "AC/DC - Shoot To Thrill (Back to Black)
var view_label = highlighted_label + ' (<i>' + song.album.name + '</i>)';
return view_label;
}
}); |
What you have works, but is a bit awkward. Your using the highlighter method to essentially customise the html rendered, which doesn't make sense. Given highlighter has a specific purpose (to highlight the matched part). You can just leave the highlighter method alone if you change.
To be:
And then change updater from:
To be:
|
@gcoop: wouldn't that cause highlighter and matcher also look through album.name part? I'd like to only match against Artist.name - Song.Title part. |
True it would :) |
If highlighter is not supposed to be used like in my example, maybe there should be another function introduced for this puprose? @fat ? |
Have a look at #4025. You had the same issue I did, at the same time :) |
Thanks. I will watch this PR, I hope it gets merged :) |
Question: In my case How to make o that typehead gets its values once and that it. No requests any more? |
@Serhioromano: Try to replace the function after his 1st call by the labels received. It seems to work for me... $(selector).typeahead({ source: function (query, process) { labels = []; $.getJSON('your_url', function(data){ $.each(data, function(i, elem){ ... }); process(labels); }); this.source = labels; }, updater: function(... }); |
Hello, I have a question... Does the updater get it on empty field? I found a hole in my use case... For example, if a user filled the typeahead field, pick a choice, the updater update the hidden field, but if the user then clear out the field he just filled, the updater doesn't seems to get it on blur for instance and the hidden field stays with the previous id of the key selected previouly... I try with a naive if like this updater: function (item) { if(! item) {update the hidden field and return item} else {return false}} Then I go for this out side of typeahead : jQuery(document).ready(function(){ Thanks to point to the rigth direction if I am wrong and miss something... |
This solution not even works perfectly in case where the user only earase a couples of characters a the end of the entry by mistake... So it needs a kind of double check on blur... |
I tried to use typeahead with asp.net mvc 4 application. I used:
or
it works. But if I change to
it does not work. It seems it ask for either local or prefetch. My questions: |
@yli01 This issue is about Bootstrap's old typeahead widget, so your problem isn't relevant here. We recommend Twitter's Typeahead.js. For problems with it, ask at their project: https://github.com/twitter/typeahead.js |
@fat: From existing pull request (#3250) against 2.1.0-wip. Sorry for not submitting it against a *-wip branch earlier.
This is a simple change to allow both synchronous and asynchronous data sources for the typeahead widget via a function/callback. This references issue #1336. Example:
Because of the recently-added "updater" option, you can also handle objects: