I'm working of this code,
<script>
autocompleteRemote = new Backbone.AutocompleteList({
url: function() { return 'http://ws.audioscrobbler.com/2.0/?method=artist.search&api_key=cef6d600c717ecadfbe965380c9bac8b&format=json&' + $.param({ artist: $('form#autocomplete-remote input[name=search]').val() }); },
filter: null,
el: $('form#autocomplete-remote input[name=search]'),
template: _.template('<p><%= name.replace(new RegExp("(" + $("form#autocomplete-remote input[name=search]").val() + ")", "i") ,"<b>$1</b>") %></p>'),
delay: 500,
minLength: 3,
value: function(model) { return model.get('name') },
}).resultsView.collection.parse = function(resp) {
return resp.results.artistmatches.artist;
};
</script>
But I'm trying to connect it to the tmdb api like this,
autocompleteRemote = new Backbone.AutocompleteList({
url: function() {
return 'http://api.themoviedb.org/3/search/movie?api_key=' + api + '&' + $.param({query: $('form#autocomplete-remote input[name=search]').val()})
},
filter: null,
el: $('form#autocomplete-remote input[name=search]'),
template: _.template(
'<p><%= name.replace(new RegExp("(" + $("form#autocomplete-remote input[name=search]").val() + ")", "i") ,"<b>$1</b>") %></p>'
),
delay: 500,
minLength: 3,
value: function(model) { return model.get('name') }
,
})
.resultsView.collection.parse = function(resp) {
return resp.results.moviematches.query;
};
var api = 'a8f7039633f206xx42cd8a28d7cadad4'
As you can see I changed a few things like the url and put the api key in a var to clean up the code a bit. I also changed the word artist to query so it would give me back the right url. But I'm getting a error in the console log and I'm drawing a blanc.
Uncaught TypeError: Cannot read property 'query' of undefined
Backbone.AutocompleteList.resultsView.collection.parse
.extend.set
options.success
fire
self.fireWith
done
callback
The source material can be found here -> http://aghull.github.io/coding/2013/03/09/Backbone-autocomplete-lists/ Autocomplete using remote Collection
Here is a nice resource which will help to find out response body. As I can see from test response generated there, there is no moviematches property. You need resp.results which is just a collection (array) of objects (movies I guess).
So you need to change your code to:
var api = 'a8f7039633f206xx42cd8a28d7cadad4';
autocompleteRemote = new Backbone.AutocompleteList({
url: function() {
return 'http://api.themoviedb.org/3/search/movie?api_key=' + api + '&' + $.param({query: $('form#autocomplete-remote input[name=search]').val()})
},
filter: null,
el: $('form#autocomplete-remote input[name=search]'),
template: _.template(
'<p><%= name.replace(new RegExp("(" + $("form#autocomplete-remote input[name=search]").val() + ")", "i") ,"<b>$1</b>") %></p>'
),
delay: 500,
minLength: 3,
value: function(model) { return model.get('name') }
,
}).resultsView.collection.parse = function(resp) {
return resp.results;
};
I tried to make a comment but it became an answer :)
Edit:
Use this fiddle for tests. Place correct API_KEY and try again. I have tried with your existing api_key, but it's invalid.
Related
I'm using the Twitter typeahead.js library for typeahead search with a single data source /api/domains.
I'd now like to add two more sources using other API endpoints:
/api/ips
/api/hostnames
How would I accomplish this? Do I need to use the BloodHound engine for this functionality?
Existing Code
<script>
$('#header').on('click', '.tt-selectable', function() {
window.location.href = "/explore/" + $(this).attr('data-domain');
});
var substringMatcher = function(strs) {
return function findMatches(q, cb) {
var matches, substringRegex;
// an array that will be populated with substring matches
matches = [];
// regex used to determine if a string contains the substring `q`
substrRegex = new RegExp(q, 'i');
// iterate through the pool of strings and for any string that
// contains the substring `q`, add it to the `matches` array
$.each(strs, function(i, str) {
if (substrRegex.test(str)) {
matches.push(str);
}
});
cb(matches);
};
};
$.getJSON('/api/domains')
.done(function( json ) {
populateSuggestions(json.domains);
})
.fail(function( jqxhr, textStatus, error ) {
var err = textStatus + ", " + error;
console.log( "Request Failed: " + err );
});
const populateSuggestions = function(data) {
$('.typeahead').typeahead({
hint: true,
highlight: true,
minLength: 1
}, {
displayKey: 'name',
limit: 10,
source: substringMatcher(data),
templates: {
suggestion: function (data) {
return "<div data-domain=" + data + ">" + data + "</div>"
}
}
});
}
</script>
Existing API response
{
domains: [
"a.com",
"b.com",
"c.com",
"d.com" ]
}
Do you want the suggestions differentiated by the source? I would expect so, since one source is domains, one is IP addresses (I presume?) and the other is hostnames. The first two I would expect someone to be typing in very different entries and getting back very different data.
Anyway, that's frequently how I use typeahead - similar searches but with multiple sources - and yes I use Bloodhound to set up each source. Then for each bloodhound source I have a separate JSON object in the typeahead setup. Like this:
$('#searchbox .typeahead').typeahead({
hint: true,
highlight: true,
autoselect: true,
minLength: 2
},
{
name: 'other',
display: 'addr',
source: otherBH,
templates: {
header: "<span class='typeahead-header'>Static</span>"
}
},
{
name: 'lookupSvc',
display: 'lookupSvc',
source: lookupServiceBH,
templates: {
header: "<span class='typeahead-header'>AJAX</span>"
}
}
...
I am using select2 in an express app to make an input box where users can select subjects from a list, and can update this list with any newly added options.
The thing I'm struggling with is that select2 runs client-side, whereas any data I use to seed my <option> tags (that I want to append new options to) is server-side.
I want users to be able to add subjects that don't exist in the original list, so that future users will be presented with newly added options (as well as the original ones)
These are the options I've considered for achieving this (in increasing desirability):
Add new <option>Subject</option> html tags for each added tag
Push new tags to an array, and seed the <option>s from this array
Seed the <option> from a json object, and update this object on tag creation
Seed the <option> from an external database (e.g. mongoose), and update this on tag creation
As far as I can see, all of these options require that my client-side code (select2-js) talks to server-side code (where my array, .json file or mongoose schema would be), and I have no idea how to go about doing this.
In my current approach I am attempting to to specify a "local" json file as my data source in my select2 call (see here). However, this doesn't seed the database with any options, so this isn't working as I expected.
I then check if each new tag exists in an array (dataBase), and add it to the database if not:
// Data to seed initial tags:
var dataBase = [
{ id: 0, text: 'Maths'},
{ id: 1, text: 'English'},
{ id: 2, text: 'Biology'},
{ id: 3, text: 'Chemistry'},
{ id: 4, text: 'Geography'}
];
$(document).ready(function() {
$('.select2-container').select2({
ajax: {
url: '../../subjects.json',
dataType: 'json',
},
width: 'style',
multiple: true,
tags: true,
createTag: function (tag) {
var isNew = false;
tag.term = tag.term.toLowerCase();
console.log(tag.term);
if(!search(tag.term, dataBase)){
if(confirm("Are you sure you want to add this tag:" + tag.term)){
dataBase.push({id:dataBase.length+1, text: tag.term});
isNew = true;
}
}
return {
id: tag.term,
text: tag.term,
isNew : isNew
};
},
tokenSeparators: [',', '.']
})
});
// Is tag in database?
function search(nameKey, myArray){
for (var i=0; i < myArray.length; i++) {
if (myArray[i].text.toLowerCase() === nameKey.toLowerCase()) {
return true
}
}
return false
};
However, this approach will add the new tags to an array that is destroyed once I refresh the page, and new tags are not stored.
How can I modify this to load server-side data (json, mongoose document or anything else that is considered a best practice), and update this data with newly added options (that pass my tests)?
On your server-side, you can have an api that maintains and returns the tag array.
If you want the array to persist even after server shutdown, you can store the tags array in a database.
Server side:
let dataBase = [
{ id: 0, text: 'Maths'},
{ id: 1, text: 'English'},
{ id: 2, text: 'Biology'},
{ id: 3, text: 'Chemistry'},
{ id: 4, text: 'Geography'}
];
//Assuming you have a nodejs-express backend
app.get('/tags', (req,res) => {
res.status(200).send({tags: dataBase});
} );
Client Side:
$(document).ready(function() {
dataBase=[];
$.get("YOUR_SERVER_ADDRESS/tags", function(data, status){
console.log("Data: " + data + "\nStatus: " + status);
dataBase = data;
});
$('.select2-container').select2({
data: dataBase,
placeholder: 'Start typing to add subjects...',
width: 'style',
multiple: true,
tags: true,
createTag: function (tag) {
var isNew = false;
tag.term = tag.term.toLowerCase();
console.log(tag.term);
if(!search(tag.term, dataBase)){
if(confirm("Are you sure you want to add this tag:" + tag.term)){
dataBase.push({id:dataBase.length+1, text: tag.term});
isNew = true;
//Update the tags array server side through a post request
}
}
return {
id: tag.term,
text: tag.term,
isNew : isNew
};
},
tokenSeparators: [',', '.']
})
});
// Is tag in database?
function search(nameKey, myArray){
for (var i=0; i < myArray.length; i++) {
if (myArray[i].text.toLowerCase() === nameKey.toLowerCase()) {
return true
}
}
return false
};
You can use select2:select and select2:unselect event for this.
var dataBase = [{
id: 0,
text: 'Maths'
},
{
id: 1,
text: 'English'
},
{
id: 2,
text: 'Biology'
},
{
id: 3,
text: 'Chemistry'
},
{
id: 4,
text: 'Geography'
}
];
$(document).ready(function() {
$('.select2-container').select2({
data: dataBase,
placeholder: 'Start typing to add subjects...',
width: 'style',
multiple: true,
tags: true,
createTag: function(tag) {
return {
id: tag.term,
text: tag.term,
isNew: true
};
},
tokenSeparators: [',', '.']
})
$(document).on("select2:select select2:unselect", '.select2-container', function(e) {
var allSelected = $('.select2-container').val();
console.log('All selected ' + allSelected);
var lastModified = e.params.data.id;
console.log('Last Modified ' + lastModified);
var dbIdArray = dataBase.map((i) => i.id.toString());
var allTagged = $('.select2-container').val().filter((i) => !(dbIdArray.indexOf(i) > -1))
console.log('All Tagged ' + allTagged);
});
});
.select2-container {
width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
<select class="select2-container"></select>
Here's what I've ended up with (thanks to both answers):
1. Set up a Mongoose DB to hold subjects:
models/subjects.js
var mongoose = require("mongoose");
var SubjectSchema = new mongoose.Schema({
subject: { type: String },
});
module.exports = mongoose.model("Subjects", SubjectSchema);
2. Set up api routes in node js express backend:
routes/api.js
var express = require("express");
var router = express.Router();
var Subjects = require("../models/subjects");
// GET route for all subjects in db
router.get("/api/subjects/all", function(req, res){
Subjects.find().lean().exec(function (err, subjects) {
return res.send(JSON.stringify(subjects));
})
});
// POST route for each added subject tag
router.post("/api/subjects/save", function(req, res){
var newSubject = {};
newSubject.subject = req.body.subject;
console.log("Updating db with:" + newSubject);
var query = {subject: req.body.subject};
var options = { upsert: true, new: true, setDefaultsOnInsert: true };
// Find the document
Subjects.findOneAndUpdate(query, options, function(error, subject) {
if (error) return;
console.log("Updated db enry: " + subject);
});
return res.send(newSubject);
});
3. Set up select2 input field:
public/js/select2.js
var dataBase=[];
$(document).ready(function() {
// Get all subjects from api (populated in step 2) and push to dataBase array
$.getJSON('/api/subjects/all')
.done(function(response) {
$.each(response, function(i, subject){
dataBase.push({id: subject._id, text: subject.subject});
})
console.log("dataBase: " + dataBase);
})
.fail(function(err){
console.log("$.getJSON('/api/subjects/all') failed")
})
// Get data from api, and on 'selecting' a subject (.on("select2:select"), check if it's in the dataBase. If it is, or the user confirms they want to add it to the database, send it to POST route, and save it to our Subjects db.
$('.select2-container')
.select2({
ajax: {
url : "/api/subjects/all",
dataType: 'json',
processResults: function (data) {
return {
results: $.map(data, function(obj) {
return { id: obj._id, text: obj.subject };
})
};
}
},
placeholder: 'Start typing to add subjects...',
width: 'style',
maximumSelectionLength: 5,
multiple: true,
createTag: function(tag) {
return {
id: tag.term,
text: tag.term.toLowerCase(),
isNew : true
};
},
tags: true,
tokenSeparators: [',', '.']
})
.on("select2:select", function(e) {
if(addSubject(dataBase, e.params.data.text)){
console.log(e.params.data.text + " has been approved for POST");
ajaxPost(e.params.data.text)
} else {
console.log(e.params.data.text + " has been rejected");
var tags = $('#selectSubject select').val();
var i = tags.indexOf(e.params.data.text);
console.log("Tags: " + tags);
if (i >= 0) {
tags.splice(i, 1);
console.log("post splice: " + tags);
$('select').val(tags).trigger('change.select2');
}
}
})
function ajaxPost(subject){
console.log("In ajaxPost");
var formData = {subject : subject}
$.ajax({
type : "POST",
contentType : "application/json",
url : "/api/subjects/save",
data : JSON.stringify(formData),
dataType : 'json'})
.done(console.log("Done posting " + JSON.stringify(formData)))
.fail(function(e) {
alert("Error!")
console.log("ERROR: ", e);
});
}
function addSubject(subjects, input) {
if (!input || input.length < 3) return false
var allSubjects = [];
$.each(subjects, function(i, subject){
if(subject.text) allSubjects.push(subject.text.toLowerCase())
});
console.log("Here is the entered subject: " + input);
if(allSubjects.includes(input)){
console.log(input + " already exists")
return true
}
if(confirm("Are you sure you want to add this new subject " + input + "?")){
console.log(input + " is going to be added to the database");
return true
}
console.log(input + " will NOT to added to the database");
return false
}
});
This works, but I would love to hear feedback on this approach!
I've created a search bar, but when the data is gathered from the user, it displays the default data over again rather then the users new search criteria.
I'm resetting the collection and giving it a new URL when the user searches, but it doesn't seem to update correctly, and I'm having trouble figuring out where my problem(s) are.
(function(){
'use strict';
var red = red || {};
//model////////////////////////////////////////////////
red.RedditModel = Backbone.Model.extend({
defaults: {
urlTarget: $('#textBox').val(),
urlStart: 'https://www.reddit.com/r/',
urlEnd: '.json'
},
initialize: function() {
this.on('change:urlTarget', function() {
console.log('The Url Target has changed to ' + this.get("urlTarget"));
});
this.on('change:concatURL', function() {
console.log('The model Url has changed to ' + this.get("concatURL"));
});
this.on('change:url', function() {
console.log('The collection url has changed to: ' + this.get('url'));
});
}
});
var redditModel = new red.RedditModel();
var fullURL = new red.RedditModel({
concatURL: redditModel.attributes.urlStart + redditModel.attributes.urlTarget + redditModel.attributes.urlEnd
});
var listElmement,
$list = $('.list');
//collections//////////////////////////////////////////
red.redditCollection = Backbone.Collection.extend({
model: red.RedditModel,
url: fullURL.attributes.concatURL,
parse: function(response) {
var redditData = response.data.children;
return redditData;
}
});
//view////////////////////////////////////
red.RedditView = Backbone.View.extend({
model: fullURL,
collection: redditCollection,
el: '.searchBar',
events: {
'click .searchButton': function(e) {
this.updateModel(e);
this.updateCollection(e);
},
'change #textBox': 'initialize'
},
updateModel: function() {
this.$urlTarget = $('#textBox').val()
this.model.set('urlTarget', this.$urlTarget);
this.model.set('concatURL', redditModel.attributes.urlStart + this.$urlTarget + redditModel.attributes.urlEnd);
},
updateCollection: function() {
this.collection.reset();
this.$urlTarget = $('#textBox').val();
var newUrl = redditModel.attributes.urlStart + this.$urlTarget + redditModel.attributes.urlEnd;
this.collection.add({ urlTarget: this.$urlTarget });
this.collection.add({ url: newUrl });
console.log(newUrl);
},
tagName: 'li',
className: 'listItems',
initialize: function() {
$list.html('');
this.collection.fetch({
success: function(redditData) {
redditData.each(function(redditData) {
redditData = redditData.attributes.data.title
listElmement = $('<li></li>').text(redditData);
$list.append(listElmement);
})
}
});
},
render: function() {
}
});
var redditCollection = new red.redditCollection({
redditModel,
fullURL
});
var myRedditView = new red.RedditView({
model: redditModel,
collection: redditCollection
});
$('.page').html(myRedditView.render());;
})();
Parse within the model, and use it for its intended purpose. No need to store the reddit url and other search related info in a model.
red.RedditModel = Backbone.Model.extend({
parse: function(data) {
return data.data;
},
})
Since you already take care of the reddit url here. Don't be afraid to make yourself some utility functions and getters/setters in your Backbone extended objects (views, model, collection, etc).
red.RedditCollection = Backbone.Collection.extend({
url: function() {
return 'https://www.reddit.com/r/' + this.target + this.extension;
},
initialize: function(models, options) {
this.extension = '.json'; // default extension
},
setExtension: function(ext) {
this.extension = ext;
},
setTarget: function(target) {
this.target = target;
},
parse: function(response) {
return response.data.children;
}
});
Don't be afraid to have a lot of views, Backbone views should be used to wrap small component logic.
So here's the item:
red.RedditItem = Backbone.View.extend({
tagName: 'li',
className: 'listItems',
render: function() {
this.$el.text(this.model.get('title'));
return this;
}
});
Which is used by the list:
red.RedditList = Backbone.View.extend({
tagName: 'ul',
initialize: function() {
this.listenTo(this.collection, 'sync', this.render);
},
render: function() {
this.$el.empty();
this.collection.each(this.renderItem, this);
return this;
},
renderItem: function(model) {
var view = new red.RedditItem({ model: model });
this.$el.append(view.render().el);
}
});
And the list is just a sub-component (sub-view) of our root view.
red.RedditView = Backbone.View.extend({
el: '.searchBar',
events: {
'click .searchButton': 'onSearchClick',
},
initialize: function() {
// cache the jQuery element for the textbox
this.$target = $('#textBox');
this.collection = new red.RedditCollection();
this.list = new red.RedditList({
collection: this.collection,
// assuming '.list' is within '.searchBar', and it should
el: this.$('.list'),
});
},
render: function() {
this.list.render();
return this;
},
onSearchClick: function(e) {
this.collection.setTarget(this.$target.val());
console.log(this.collection.url());
this.collection.fetch({ reset: true });
},
});
Then, you only need the following to use it:
var myRedditView = new red.RedditView();
myRedditView.render();
Notice the almost non-existent use of the global jQuery selector. If you're using Backbone and everywhere you're using $('#my-element'), you're defeating the purpose of Backbone which is, in part, to apply MVC concepts on top of jQuery.
Some notes on the code posted
Take time to understand what's going on. There are several lines of code in your question that doesn't do anything, or just don't work at all.
Though it's been removed in your answer, the following doesn't make sense because the collection constructor is Backbone.Collection([models], [options]) and what you have here translates to passing an options object (using ES6 shorthand property names { a, b, c}) to the models parameter.
var redditCollection = new red.redditCollection({
redditModel,
fullURL
});
This line does nothing, because .render() doesn't do anything and doesn't return anything.
$('.page').html(myRedditView.render());
Here, you're creating a new element manually using jQuery while you have Backbone which does this for you.
$('<li></li>').text(redditData);
Don't use the attributes directly, always use .get('attributeKey') unless you have a good reason not to.
redditModel.attributes.urlStart
Favor local variables whenever you can. The listElement var here is defined at the "app" level without a need for it.
listElmement = $('<li></li>').text(redditData);
$list.append(listElmement);
A Backbone collection is automatically filled with the new instances of models on success. You do not need to re-parse that in the success callback (in addition to the ambiguity with redditData).
this.collection.fetch({
success: function(redditData) {
redditData.each(function(redditData) {
redditData = redditData.attributes.data.title;
I don't mean to be rude and I took the time to write that long answer to try to help, you, and any future reader that comes by.
I'm trying to set up links and routing with Backbone (this is my first Backbone app). In particular, I want a link of the form /restaurants/:id to trigger the show route.
This is my code:
var App = {
Models: {},
Views: {},
Collections: {}
};
// RESTAURANT SCHEMA
// name
// type
// rating (average) - virtual attribute
// points
// ratings
App.Models.Restaurant = Backbone.Model.extend({
urlRoot: '/restaurants',
defaults: {
points: 0,
ratings: 0
},
updateRating: function(points) {
this.set({points: points});
this.set({ratings: this.get('ratings') + 1});
this.rating.set({
rating: this.get('points') / this.get('ratings')
});
this.save(); // PUT /restaurants/:id PUT if model exists, POST if not
}
});
App.Collections.Restaurants = new (Backbone.Collection.extend({
model: App.Models.Restaurant,
url: '/restaurants'
}))();
App.Views.Restaurant = Backbone.View.extend({
template: _.template(
'<div class="page-header"><h1><%= name %></h1></div>' +
'<p>Type: <%= type %></p><br />' +
'<label>Enter rating: </label>' +
'<input type="number" class="form-control" min="1" max="5">'
),
events: {
'change input[type=number]': 'updateRating'
},
updateRating: function() {
var points = this.$el.$(); // TODO
this.model.updateRating(points);
},
render: function() {
var attributes = this.model.toJSON();
this.$el.html(this.template(attributes));
}
});
App.Views.Restaurants = Backbone.View.extend({
template: _.template(
'<div class="page-header"><h1>Restaurants</h1></div>' +
'<ul>' +
'<% App.Collections.Restaurants.forEach(function(restaurant){ %>' +
'<li><%= restaurant.get("name") %></li>' + // using cid's like this doesn't seem right. I think I need to get the id after saving to the database, but I haven't done that yet.
'<% }); %>' +
'</ul>'
),
render: function() {
this.$el.html(this.template());
},
events: {
'click a': function(e) {
e.preventDefault();
App.Router.navigate(e.target.pathname, {trigger: true});
}
}
});
App.Router = Backbone.Router.extend({
routes: {
"restaurants": "index",
"restaurants/:id": "show",
"restaurants/new": "new",
"restaurants/:id/edit": "edit"
},
initialize: function() {
console.log('initialize called');
var PicolaBusala = new App.Models.Restaurant({
name: "Picola Busala",
type: "Italian"
});
var Benihanna = new App.Models.Restaurant({
name: "Benihanna",
type: "Asian"
});
var LemonLeaf = new App.Models.Restaurant({
name: "Lemon Leaf",
type: "Thai"
});
var picolaBusala = new App.Views.Restaurant({model: PicolaBusala});
var benihanna = new App.Views.Restaurant({model: Benihanna});
var lemonLeaf = new App.Views.Restaurant({model: LemonLeaf});
App.Collections.Restaurants.add(PicolaBusala);
App.Collections.Restaurants.add(Benihanna);
App.Collections.Restaurants.add(LemonLeaf);
App.Views.restaurantsView = new App.Views.Restaurants({collection: App.Collections.Restaurants});
App.Views.restaurantsView.render();
$("#app").html(App.Views.restaurantsView.el);
},
start: function() {
console.log('start called');
Backbone.history.start({pushState: true});
},
index: function() {
console.log('index called');
App.Collections.Restaurants.fetch();
$("#app").html(App.Views.restaurantsView.el);
},
show: function(id) {
console.log('show called');
console.log('id: ', id);
},
new: function() {
},
edit: function() {
}
});
$(function() {
App.Router = new App.Router(); // because a) initialize() needs to be called once the DOM loads and b) App.Router needs to be instantiated for .navigate()
App.Router.start();
})
The particular error I get when I click the /restaurants/:id link is Uncaught SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'file:///Users/adamzerner/code/getable_challenge/restaurants/c3' cannot be created in a document with origin 'null'.
What am I doing wrong?
The likely problem is that you're not running this on a server. You need to set up a local server using something like MAMP or WAMP or Node for example so you'll end up accessing your page through the browser at a location like localhost:8080. This will allow you to load local content like a JSON file.
If this doesn't solve your problem try taking a look at Javascript history.PushState not working?
I am working on autosuggestion task and i have requirement like if typeahead suggestion textbox is empty shows default options on suggestion list like below jsfiddle
http://jsfiddle.net/5xxYq/
This example working perfectly. but I have retrieved a suggestion list from remote using bloodhound is not working listed below my piece of code:
var sos_adapt = new Bloodhound({
datumTokenizer: function(d) {
return Bloodhound.tokenizers.whitespace(d.value);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'appsearch?ty=so&cid=%CID&query=%QUERY',
replace: function(url, query) {
return url.replace('%QUERY', query).replace('%CID', customer_id);
},
filter: function(sos) {
return $.map(sos, function(sos) {
return {
so_desc: sos.so_desc,
so_no: sos.so_no,
so_details: sos.so_no + " : " + sos.so_desc,
customer_id: sos.customer_id,
customer_details: sos.customer_id + " : " + sos.customer_name
};
});
},
ajax: {
global: false,
beforeSend: function(xhr)
{
}
}
}
});
//initialize the bloodhound suggestion engine
sos_adapt.initialize();
$('#so_details').typeahead(null, {
displayKey: 'so_no',
source: sos_adapt.ttAdapter(),
minLength: 0,
templates: {
empty: [
'<div class="sug_items">',
'unable to find any so#!',
'</div>'
].join('\n'),
suggestion: Handlebars.compile([
'<div class="sug_items"><p class="repo-language">SO# : {{so_no}}</p>',
'<p class="repo-name">{{so_desc}}</p></div>'
].join(''))
}
});
my code was working perfect when user type text on textbox. but, when user focus empty textbox bloodhound not sending remote request for suggestion. but, i tried code for on focus show suggestion list on typeahead textbox below:
$("#so_details").on("click", function() {
var ev = $.Event("keydown");
ev.keyCode = ev.which = 40;
$(this).trigger(ev);
return true;
});
this code pick from above jsfiddle example, can any one guide me how to do that? any help will be appreciated.