Typeahead v0.10.2 & Bloodhound - работа с вложенными объектами JSON
UPDATE
Основываясь на правильном ответе от @BenSmith (https://stackoverflow.com/users/203371/BenSmith), я смог найти свою проблему и выяснил, что я не перешел через свою иерархию JSON должным образом. Вот рабочий код:
// instantiate the bloodhound suggestion engine
var engine = new Bloodhound({
datumTokenizer: function (datum) {
return Bloodhound.tokenizers.whitespace(datum.title);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: "SampleData.json",
filter: function (data) {
//console.log("data", data.response.songs)
return $.map(data.response.songs, function (song) {
return {
title: song.title,
artistName: song.artist_name
};
});
}
}
});
// initialize the bloodhound suggestion engine
engine.initialize();
// instantiate the typeahead UI
$('#prefetch .typeahead').typeahead(
{
hint: true,
highlight: true,
minLength: 1
},
{
name: 'engine',
displayKey: 'title',
source: engine.ttAdapter(),
templates: {
empty: [
'<div class="empty-message">',
'unable to find any results that match the current query',
'</div>'
].join('\n'),
suggestion: Handlebars.compile('<p><strong>{{title}}</strong> by {{artistName}}</p>')
}
});
Спасибо @BenSmith за помощь!
Оригинальный вопрос
Я новичок в работе с Typeahead и Bloodhound. Документация не очень помогает. У меня есть набор объектов JSON, которые я получаю от API, с которым я работаю. Я пытаюсь понять, как перемещаться по моим объектам JSON, чтобы Bloodhound мог их понять.
Цель: пользователь начнет вводить имя песни. Затем автозаполнение отобразит список имен песен и исполнителя, в котором он был выполнен.
Например: Перезвоны в полночь Мастодоном
Я использую последние версии каждой библиотеки:
https://twitter.github.io/typeahead.js/
Образец JSON (SampleData.json):
{"response": {"status": {"version": "4.2", "code": 0, "message": "Success"}, "songs": [{"title": "Chimes At Midnight", "artist_name": "Mastodon", "artist_foreign_ids": [{"catalog": "7digital-AU", "foreign_id": "7digital-AU:artist:29785"}, {"catalog": "7digital-UK", "foreign_id": "7digital-UK:artist:29785"}], "tracks": [], "artist_id": "ARMQHX71187B9890D3", "id": "SOKSFNN1463B7E4B1E"}, {"title": "Down Under", "artist_name": "Men at Work", "artist_foreign_ids": [{"catalog": "7digital-AU", "foreign_id": "7digital-AU:artist:50611"}], "tracks": [], "artist_id": "AR4MVC71187B9AEAB3", "id": "SORNNEB133A920BF86"}]}}
Используйте этот сайт http://json.parser.online.fr/, чтобы легко форматировать JSON.
JSON, я вернусь, всегда будет в том же формате, но содержит разные данные. В этом примере "дорожки" имеют значение NULL. Другие результаты будут иметь данные. Мне также нужно будет иметь доступ к этим данным.
Я использую последнюю версию JQuery. Вот что я включил в мою страницу html:
<script src="Scripts/jquery-2.1.1.min.js"></script>
<script src="Scripts/typeahead.bundle.min.js"></script>
Вот HTML:
<div id="prefetch">
<input class="typeahead" type="text" placeholder="Songs...">
</div>
Вот script:
// instantiate the bloodhound suggestion engine
var engine = new Bloodhound({
datumTokenizer: function (d) { return Bloodhound.tokenizers.whitespace(d.tokens.join(' ')); },
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: "SampleData.json",
filter: function (response) {
return response.engine;
}
}
});
// initialize the bloodhound suggestion engine
engine.initialize();
// instantiate the typeahead UI
$('#prefetch .typeahead').typeahead(
{
hint: true,
highlight: true,
minLength: 1
},
{
name: 'songs',
displayKey: function (engine) {
return engine.songs.artist_name;
},
source: engine.ttAdapter()
});
Когда я пытаюсь запустить этот код, я получаю следующую ошибку:
Uncaught TypeError: Невозможно прочитать "токены" свойств undefined
Любая помощь или руководство здесь будут очень признательны. Мне просто нужно знать, как получить данные JSON, с которыми я работаю, работая с Typeahead/Bloodhound.
Спасибо!
Ответы
Ответ 1
Вам нужно написать функцию фильтра, чтобы он создавал массив объектов javascript для использования в качестве баз данных. Следующее должно работать (я не тестировал это):
filter: function (response) {
return $.map(response.songs, function (song) {
return {
title: song.title,
artistName: song.artist_name
};
});
}
(пример функции фильтра можно найти здесь)
И измените ваш datumtokenizer на:
datumTokenizer: function (datum) {
return Bloodhound.tokenizers.whitespace(datum.title);
}
также измените свой экран дисплея на:
displayKey: 'title'
Так как это ключ, который Typeahead будет использовать для поиска.
Что касается отображения имени песни и исполнителя в списке подсказок, я предлагаю вам использовать шаблоны (например, Handlebars) для отображения результатов. См. Пример "Пользовательский шаблон" в странице примеров типов.. Ваша надбавка к предложению будет выглядеть примерно так:
suggestion: Handlebars.compile('<p><strong>{{title}}</strong> by {{artistName}}</p>')
Ответ 2
Мой ответ ничего нового, а просто обновление для v0.11 твиттера typeahead. Как всегда, перенаправляйте свои upvotes (если есть) к исходному ответу.
Дружелюбное напоминание всем, кто все еще использует Twitter-Typeahead заключается в том, чтобы отойти от этого репозитория, поскольку он больше не поддерживается. Вместо этого перенаправьте себя на corejavascript/typeahead.js, который вилка исходного репозитория и тот же автор (@JakeHarding) поддерживает этот репозиторий.
От v0.10 до v0.11 несколько вещей изменились, и поэтому ответ должен быть. Вот мой новый код для этой более новой версии.
HTML
<div id="prefetch">
<input class="typeahead" type="text" placeholder="Countries">
</div>
JS
var tags = new Bloodhound({
datumTokenizer: function(datum) {
return Bloodhound.tokenizers.whitespace(datum.name);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
prefetch: {
url: 'http://www.yourwebsite.com/js/data.json',
cache: false,
transform: function(response) {
return $.map(response, function (tag) {
return {
name: tag.tagName,
id: tag.tagId
}
});
}
}
});
$('#prefetch .typeahead').typeahead({
minLength: 3,
highlight: true
}, {
name: 'tags-dataset',
source: tags,
display: 'name'
});
Что изменилось:
- В
prefetch
нет опции filter
. Вместо этого вы должны использовать transform
.
-
displayKey
в < <26 > функция была изменена на просто display
.
-
cache
в опции transform
установлено значение false, так что источник данных загружается каждый раз. Это полезно для тестирования, но на рабочем сервере эта опция должна быть отключена, если требуется кэширование данных.
В качестве дополнительной заметки для людей, которые пробуют этот пример с помощью разные источники данных с cache
установлены в true. Вы должны всегда запускать window.localStorage.clear();
в консоли, чтобы очистить уже присутствует локальное хранилище, чтобы можно было получить новые данные. В противном случае будут использованы старые данные, и вы можете подумайте, почему ваш код не работает.
Вот пример рабочего JSFIDDLE, чтобы вы начали. Несколько замечаний:
- Я не знал, есть ли CDN для typeahead, поэтому я просто вставлял весь код java-кода типа ahead. В нижней части страницы вы можете посмотреть мою функцию.
- Источник данных указывает на ссылку, которая является файлом, размещенным в моей учетной записи Dropbox. В случае, если я удалю этот файл, этот пример не будет работать вообще. Следовательно, вам нужно предоставить собственный источник. Вот содержимое этого файла -
[{"tagId":9,"tagName":"Action"},{"tagId":10,"tagName":"Adventure"},{"tagId":6,"tagName":"Books"},{"tagId":11,"tagName":"Fantasy"},{"tagId":2,"tagName":"Games"},{"tagId":1,"tagName":"Movies"},{"tagId":3,"tagName":"Music"},{"tagId":8,"tagName":"News"},{"tagId":4,"tagName":"Office"},{"tagId":5,"tagName":"Security"},{"tagId":7,"tagName":"TV-Shows"}]