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;
}
Related
here's what I tried in model1.js:
model1.remotemethod1 = function(id, data, cb) {
var model2 = app.models.model2;
model2.remotemethod2(id, data).then(response => {
cb(null, true);
});
};
this is my model2.js :
it has the definition of remotemethod2 .
'use strict';
module.exports = function(model2) {
model2.remotemethod2 = function(id, data, cb) {
var promise;
let tags = data.tags ? data.tags.slice() : [];
delete data.categories;
delete data.tags;
promise = model2.upsertWithWhere({
or: [
{barcode: data.barcode},
{id: data.id},
],
}, data);
promise.then(function(model2) {
model2.tags.destroyAll().then(function() {
for (let i = 0; i < tags.length; i++) {
model2.tags.add(tags[i]);
}
cb(null, model2);
});
});
};
};
But it dos not work !
I think that app.models.model2 does not give me the model with its remote methods ! maybe I should get an instance of the model2 !
var (VAR-NAME)= (CURRENT-MODEL).app.models.(ANOTHER_MODEL);
you now can use the other model by calling one of its methods for example
EX:
VAR-NAME.create();
Declare remotemethod1 in server.js app.start and you'll have access to the correct app.models.model2 and you will be able to use its remote method.
app.start = function() {
model1.remotemethod1 = (id, data, cb) => {
var model2 = app.models.model2;
model2.remotemethod2(id, data).then(response => {
cb(null, true);
});
};
model1.remoteMethod(
'remotemethod1', {
http: { path: '/remotemethod1', verb: 'post', status: 200, errorStatus: 400 },
accepts: [{arg: 'id', type: 'number'}, {arg: 'id', type: 'object'}],
returns: {arg: 'status', type : 'string' }
}) ;
}
// The rest of app.start...
EDIT you can also create the remote method will the correct app context with a file located in myprojectname/server/boot
`module.exports(app) {
/* Create remote methods here */
}`
i am using the following code to enable typeahead on input field
some times the regions are not displayed but when i see the "network xhr request" in inspect element. the url does return data.
Another issue the limit is not working in this example. i have tried different numbers but none of them works
var Regions = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('label'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'https://www.domain.com/getcities?query=%QUERY',wildcard: '%QUERY'
},
limit: 10
});
Regions.initialize();
var hotels = new Bloodhound({
datumTokenizer: function (datum) {
return Bloodhound.tokenizers.whitespace(datum.value);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'https://www.domain.com/gethotels?query=%QUERY',
wildcard: '%QUERY',
},
limit: 10
});
hotels.initialize();
function typeAhead()
{
$('#myinput').typeahead({
hint: true,
highlight: true,
minLength: 2
},
{
name: 'nba-teams',
displayKey: 'label',
source: Regions.ttAdapter() ,
templates: {
header: '<h3 class="league-name">Cities and regions</h3>'
}
},
{
name: 'nhl-teams',
displayKey: 'label',
source: hotels.ttAdapter() ,
templates: {
header: '<h3 class="league-name">Hotels</h3>'
}
});
}
Please check with below code.
var Regions = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('label'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'https://www.domain.com/getcities?query=%QUERY',wildcard: '%QUERY'
}
});
Regions.initialize();
var hotels = new Bloodhound({
datumTokenizer: function (datum) {
return Bloodhound.tokenizers.whitespace(datum.value);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'https://www.domain.com/gethotels?query=%QUERY',
wildcard: '%QUERY',
}
});
hotels.initialize();
function typeAhead(){
$('#myinput').typeahead({
hint: true,
highlight: true,
minLength: 2
},
{
name: 'nba-teams',
displayKey: 'label',
source: Regions.ttAdapter() ,
limit: 10,
templates: {
header: '<h3 class="league-name">Cities and regions</h3>'
}
},
{
name: 'nhl-teams',
displayKey: 'label',
source: hotels.ttAdapter() ,
limit: 10,
templates: {
header: '<h3 class="league-name">Hotels</h3>'
}
});
}
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.
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;
}
}
});
I have my list which is getting data from php service, the data received is in the order I need. But sencha automatically sort my list alphabetically.
Below is my code:
Ext.define('MyList', {
extend: 'Ext.dataview.List',
config: {
grouped: true,
plugins: [
{
xclass: 'Ext.plugin.PullRefresh',
pullRefreshText: 'Pull down to refresh'
},
{
xclass: 'Ext.plugin.ListPaging',
autoPaging: true,
noMoreRecordsText: 'No More Records'
}
]
},
initialize: function () {
this.callParent(arguments);
var store = Ext.create('Ext.data.Store', {
pageParam: 'page',
grouper: {
groupFn: function (record) {
return record.data.group_label;
}
},
model: 'ListItem',
proxy: {
type: 'ajax',
url: '/m/services/activity_list_items.php',
reader: {
type: 'json',
rootProperty: 'root.results'
}
}
});
var template = Ext.create('GenericListItem', {
hascounts: true,
hasicon: true,
varmap: {
descr: 'subtext',
count: 'sub_item_cnt',
itemid: 'itemid',
uniqid: 'uniqid'
}
});
var emptyText = 'Recent Activity Items';
this.setStore(store);
this.setItemTpl(template);
this.setEmptyText(emptyText);
}
});
How can I avoid the auto sorting of list?
Add the following to your store config.
remoteSort : true,
remoteSort defaults to false in sencha. So sencha automatically sorts in the client side. Check the link for more details http://docs.sencha.com/touch/2-0/#!/api/Ext.data.Store-cfg-remoteSort
Just remove this:
grouped: true
from your list config if you don't want a header for each item and compulsory to remove this:
grouper: {
groupFn: function (record) {
return record.data.group_label;
}
}
from your store because basically in your situation grouper property are using for grouping your item alphabetically based on your group_label field. Hope it helps :)