Why are the typeahead suggestions undefined? - typeahead

Hopefully this is not a duplicate of: Why does bloodhound.get() return undefined?
I upgraded to typeahead.js version 0.10.0. Prior versions were returning the suggestions properly. Now I am getting an undefined return with the below code:
// instantiate the bloodhound suggestion engine
var engine = new Bloodhound({
datumTokenizer: function (d) { return [d]; },
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: ["(A)labama", "Alaska", "Arizona", "Arkansas"]
});
// initialize the bloodhound suggestion engine
engine.initialize();
$('#typeahead').typeahead(null, {
source: engine.ttAdapter()
});
Here is my fiddle: http://jsfiddle.net/ucUcn/6/
Any ideas why this is happening?

The local array must contain objects, not strings themself.
// instantiate the bloodhound suggestion engine
var engine = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('d'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
local: [{
d: "(A)labama"
}, {
d: "Alaska"
}, {
d: "Arizona"
}, {
d: "Arkansas"
}]
});
// initialize the bloodhound suggestion engine
engine.initialize();
$('#typeahead').typeahead(null, {
displayKey: 'd',
source: engine.ttAdapter()
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://twitter.github.io/typeahead.js/releases/latest/typeahead.bundle.js"></script>
<input id="typeahead" />
Fiddle with above fix:
JsFiddle

As #Chad said, the result array must contains objects.
I only wanted to add that the default value used to display the suggestion is value
So you could do something like
var suggestionEngine = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: "myUrl",
filter: function (suggestions) {
var mappedResult = $.map(suggestions[1], function(suggestion) {
return { value : suggestion }
});
return mappedResult;
}
}
});

Related

bloodhound multiple dataset cause typeahead template issue

I've local elastic search server, install and running.
I instanciate 2 bloodhound object followig examples (can't post link because of reputation limitations)
If I use output as is, I have my results from my 2 datasource, no trouble.
When I want to use, remote: transform or filter option, to format the data, for using a custom template, I've trouble, the 2 template never get call.
Here's my code :
First bloodhound :
var nameSuggest = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace,
queryTokenizer: Bloodhound.tokenizers.obj.whitespace,
identify: 'nameSuggest',
sufficient: 50,
remote: {
url: 'http://localhost:9200/test2/_suggest?pretty',
prepare: function (query, settings) {
settings.type = "POST";
settings.contentType = "application/json; charset=UTF-8";
search_payload = {
"suggest": {
"text": query,
"completion": {
"field": "suggest"
}
}
};
settings.data = JSON.stringify(search_payload);
return settings;
},
transform: function(response) {
return $.map(response.suggest[0].options, function (option) {
return {
optionText: option.text,
optionId:option.payload.id
};
});
}
}
});
Second dataset:
var mailSuggest = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace,
queryTokenizer: Bloodhound.tokenizers.obj.whitespace,
identify: 'mailSuggest',
sufficient: 50,
remote: {
url: 'http://localhost:9200/test2/_suggest?pretty',
prepare: function (query, settings) {
settings.type = "POST";
settings.contentType = "application/json; charset=UTF-8";
search_payload = {
"suggestMail": {
"text": query,
"completion": {
"field": "suggest2"
}
}
};
settings.data = JSON.stringify(search_payload);
return settings;
},
transform: function(response) {
return $.map(response.suggestMail[0].options, function (option) {
return {
optionText2: option.text,
optionId2:option.payload.id
};
});
}
}
});
And typeahead:
jQuery('#topSearch').typeahead({
name:'topSearch',
hint: true,
highlight: true,
limit: 20
},
{
name: 'nameSuggest',
display: 'data',
source: nameSuggest,
templates: {
header: '<div><h3 class="">Noms</h3></div>',
suggestion: function (data) {
console.log("Name");
return '<div>'+data.optionId+' - '+data.optionText+'</div>';
}
}
},
{
name: 'mailSuggest',
display: 'data',
source: mailSuggest,
templates: {
header: '<div><h3 class="">Mails</h3></div>',
suggestion: function (data) {
console.log("Mail");
return '<div>'+data.optionText2+'</div>';
}
}
}
);
When I do :
console.log(nameSuggest);
console.log(mailSuggest);
I've two separate object, with unique names (the identify option) :
Bloodhound { identify="nameSuggest", sufficient=50, local=[0], plus...}
Bloodhound { identify="mailSuggest", sufficient=50, local=[0], plus...}
but, in the remote part of each object I can see the transform and prepare section with the two object names (there are screenshot) :
first object
seconde object
If I remove transform option from both bloodhound instances, and templates for typeahead, it works, and I'v suggestions.
If I remove transform of the second bloodhound instance and template associated, first results are displayed, withing the template, and second result are displayed raw, but it works.
If I let the second template in typeahead init, without bloodhound associated transform, the second template header is displayed, but the data undefined (normal behavior I suppose).
So, somehow, transform of the second bloodhound break something, but I can't figure out what, and how.
Do I miss something, or did something wrong ?
Solved:
I have to add the size option to the query, to tell elastic to send more result:
var mailSuggest = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace,
queryTokenizer: Bloodhound.tokenizers.obj.whitespace,
identify: 'mailSuggest',
sufficient: 50,
remote: {
url: 'http://localhost:9200/test2/_suggest?pretty',
prepare: function (query, settings) {
settings.type = "POST";
settings.contentType = "application/json; charset=UTF-8";
search_payload = {
"suggestMail": {
"text": query,
"completion": {
"field": "suggest2",
"size": 20
}
}
};
settings.data = JSON.stringify(search_payload);
return settings;
},
transform: function(response) {
return $.map(response.suggestMail[0].options, function (option) {
return {
optionText2: option.text,
optionId2:option.payload.id
};
});
}
}
});
I tried with 20 for testing prupose.

angular-ui-bootstrap causes unknown provider error when minified

After adding angular-ui-bootstrap and running grunt serve on my yeoman app, it runs perfectly and the modal I want to show is displayed correctly, but once I do a grunt build, I get an unknown provider error in my console.
<!-- This is what I added in my index.html -->
<script src="bower_components/angular-bootstrap/ui-bootstrap-tpls.js"></script>
// In app.js I have
angular.module('yeomanApp', [
'ngCookies',
'ngResource',
'ngSanitize',
'ngRoute',
'ui.bootstrap'
])
and in the controller,
.controller('myCntrl', function ($modal) {
$scope.items = ['item1', 'item2', 'item3'];
$scope.showDeleteWarning = function () {
var modalInstance = $modal.open({
templateUrl: 'deleteWarning.html',
controller: ModalInstanceCtrl,
resolve: {
items: function () {
return $scope.items;
}
}
});
modalInstance.result.then(function (selectedItem) {
$scope.selected = selectedItem;
}, function () {});
};
// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.
var ModalInstanceCtrl = function ($scope, $modalInstance, items) {
$scope.items = items;
$scope.selected = {
item: $scope.items[0]
};
$scope.ok = function () {
$modalInstance.close($scope.selected.item);
deleteVent();
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
};
Likely that you need to inject your controller dependency...
https://docs.angularjs.org/tutorial/step_05#a-note-on-minfication
.controller('myCntrl', ['$modal', function ($modal) {
/* Controller Code Here... */
}]);
I know this is an old question, but I'll post my answer here for people who come across this problem in the future.
I came across this exact problem before. The cause of your errors during minification is most likely your 'var ModalInstanceCtrl'.
Here's how I got my code to work:
var modalInstance = $modal.open({
templateUrl: 'deleteWarning.html',
controller: 'ModalInstanceCtrl', //change this to a string
resolve: {
items: function () {
return $scope.items;
}
}
});
and this line:
var ModalInstanceCtrl = function ($scope, $modalInstance, items) {
to:
angular.module('myModule').controller('ModalInstanceCtrl', function ($scope, $modalInstance, items) {
For anyone who just encountered this problem, maybe this will help.
We use customModalDefaults and customModalOptions, so we had to turn the whole return $modal.open(tempModalDefaults).result; in the show function to the following:
this.show = function (customModalDefaults, customModalOptions) {
//Create temp objects to work with since we're in a singleton service
var tempModalDefaults = {};
var tempModalOptions = {};
//Map angular-ui modal custom defaults to modal defaults defined in service
angular.extend(tempModalDefaults, modalDefaults, customModalDefaults);
//Map modal.html $scope custom properties to defaults defined in service
angular.extend(tempModalOptions, modalOptions, customModalOptions);
return $modal.open({
backdrop: customModalDefaults.backdrop,
keyboard: customModalDefaults.keyboard,
modalFade: customModalDefaults.modalFade,
templateUrl: customModalDefaults.templateUrl,
size: customModalDefaults.size,
controller: ['$scope', '$modalInstance', function ($scope, $modalInstance) {
$scope.modalOptions = tempModalOptions;
$scope.modalOptions.ok = function (result) {
$modalInstance.close(result);
};
$scope.modalOptions.close = function (result) {
$modalInstance.dismiss('cancel');
};
} ]
}).result;
};
I just ran into this problem on only one of many modals used throughout my application, and it turned out my problem was not using explicit function annotation in the resolve block of the modal configuration.
var modalInstance = $uibModal.open({
templateUrl: 'preferences.html',
controller: 'preferencesCtrl as ctrl', // this external controller was using explicit function annotation...
resolve: {
parent: [function() {
return ctrl;
}],
sectorList: ['preferencesService', function(preferencesService) { // but this was not!
return preferencesService.getSectors();
}]
}
});
Hope this saves someone else a gray hair or two...

Typeahead 0.10 prevent caching

I use twitter's typeahead 0.10 with remote url to retrieve JSON results from server.
I would like to prevent tthe client caching so that the search takes place always on the
server. How can I do that?
Please see below my code:
// instantiate the bloodhound suggestion engine
var dataSource = new Bloodhound({
datumTokenizer: function (d) {
return Bloodhound.tokenizers.whitespace(d.value);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: "../" + autocompleteInfo.ControllerName + "/" + autocompleteInfo.MethodName + "?term=%QUERY&ts=" + (new Date().getTime()),
filter: function (res) {
var data = [];
data = $.map(res, function (item) {
return { label: item.Name, id: item.Id, autocompleteInfo: autocompleteInfo, cssClass: item.Class };
});
return data;
}
},
limit: 15,
name: 'typeaheadSourceCache',
ttl: 0,
ajax: {
cache: false
}
});
dataSource.initialize();
$("#" + autocompleteInfo.AutocompleteId).typeahead({
minLength: 3,
highlight: true,
autoselect: true
},
{
displayKey: 'label',
source: dataSource.ttAdapter(),
templates: {
suggestion: Handlebars.compile(
'<div class="searchItem {{cssClass}}">{{label}}</div>'
)
}
});
Just add cache field to remote object:
remote: {
'cache': false
...
}
Look at version 10.0.2. There is now a means to clear cache via Bloodhound.js (used in association with Typeahead.js):
engine.clearRemoteCache();
Here is the documentation from twitter typeahead:
https://github.com/twitter/typeahead.js/blob/master/doc/bloodhound.md#bloodhoundclearremotecache
Try to use typeahead destroy utils, i think in your case are:
$("#" + autocompleteInfo.AutocompleteId).typeahead('destroy');
The you reinizialize $("#" + autocompleteInfo.AutocompleteId)
To fix IE issues I've came to:
remote: {
url: '/myurl?par=%QUERY',
wildcard: '%QUERY',
prepare: function (q, o) {
o.url = o.url.replace('%QUERY', encodeURIComponent(q));
o.cache = false;
return o;
}
}
prefetch: {
url: '/myurl2',
ttl: 300000, //5min
thumbprint: userName,
prepare: function(o) {
o.cache = false;
return o;
}

Backbone collection parse never fires, collection.models should have 2 items but is 0

Here is my MemberView.js ...
define([
'jquery',
'underscore',
'backbone',
'collections/MembersCollection',
'text!templates/memTemplate.html'
], function($, _, Backbone, MembersCollection, memTemplate) {
var MembersView = Backbone.View.extend({
el: $("#page"),
initialize: function() {
var that = this;
this.collection = new MembersCollection([]);
this.collection.fetch({
success : function(collection, response, options) {
that.render();
},
error: function(collection, response, options) {
console.log('members fetch error: '+response.responseText);
alert(response.responseText);
}
});
},
render: function() {
var data = { members : this.collection.models };
var compiledTemplate = _.template( memTemplate, data );
this.$el.html( compiledTemplate );
}
});
return MembersView;
});
Here is my MemberCollection.js ...
define([
'jquery',
'underscore',
'backbone',
'models/Member'
], function($, _, Backbone, Member) {
var MembersCollection = Backbone.Collection.extend({
model: Member,
initialize : function(models, options) { },
url : '/modular-backbone/server/member',
parse: function (response) {
console.log("In Parse=" + response.length);
return response;
}
});
return MembersCollection;
});
There is never a "In Parse=?" in the console so I have to assume collection.parse is not fireing. Also, if I put a break in the view.render method, collection.models is always a zero length array even though I can clearly see 2 Member records in the fetch success response. What am I missing?
Thanks a lot for your advice :-)
Unbelievable...
I went back and cleaned up a bunch of commented out lines in a few js files, ran the app again and now it's working perfectly. This makes no sense at all.

Errors When Using ember-1.0.0-pre.4.min.js

When I use ember-1.0.0-pre.4.min.js on my code, I get the following errors from Chrome's console debugger:
Uncaught TypeError: Object prototype may only be an Object or null ember-1.0.0-pre.4.min.js:18
Uncaught TypeError: Cannot call method 'extend' of undefined
Code:
Win = Em.Application.create({
View: {},
Model: {},
Controller: {}
});
Win.Model.ValuePair = Em.Object.extend({
id: null,
name: null
});
Win.View.BrandKeywordView = Em.TextField.extend({
keyDown: function () {
var value = this.get('value');
if (value) {
Win.Controller.BrandKeywordController.searchBrand(value);
console.log(Win.Controller.BrandKeywordController.content[0].id);
}
}
});
Win.Controller.BrandKeywordController = Em.ArrayProxy.create({
content: [],
searchBrand: function (brandName) {
var me = this;
$.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json; charset=utf-8',
url: 'brands/default.aspx/Search',
data: '{keyword:"' + brandName + '"}',
success: function (data) {
var brands = $.parseJSON(data.d);
me.content = [];
for (var i = 0, max = brands.length; i < max; i++) {
me.pushObject(Win.Model.ValuePair.create({ id: brands[i].Id, name: brands[i].Name }));
}
}
});
}
});
But then everything works fine when I switch to ember-1.0.beta.2.min.js.
What am I doing wrong?
Which release should I use?
Thanks in advance.
Without having studied your code in detail, my guess would be the routing API. It has completely changed between pre2 and pre3, thus is not backward compatible. Have a look at http://emberjs.com/guides/routing/
So, you really need to "migrate" your code to the new version. It will not just work with the new versions.
NOTE that the API has been freezed with pre4. So, API backward compatibility issues should not arise anymore 'til the next major version of ember js.