Typeahead/Bloodhound - Using Jquery Ajax for remote causes only a single server side request - typeahead

I need to use a jquery ajax setup in Bloodhound's remote property since I have a server side page that takes POST requests only. Everything works, but just once. Any subsequent change to the text in the typeahead input box calls the filter function, but does not fire a new server side request to fetch new data. It just filters through the data that it got in the first request. I need for it make a new request as the user removes the text and types in something else.
I am new to typeahead and I am spending way too much time trying to figure this out. Here is my code.
var users = new Bloodhound({
datumTokenizer: function (d) {
return Bloodhound.tokenizers.whitespace(d.value);
},
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'fake.jsp',
filter: function (users) {
return $.map(users, function (user) {
return {
value: user.USER_ID,
name: user.DISPLAYNAME
};
});
},
ajax: {
type: 'POST',
data: {
param: function(){
return $('#userid').val();
}
},
context: this
}
}
});
users.initialize(true);
$('#userid').typeahead({
minLength: 3,
highlight: true
}, {
name: 'userslist',
displayKey: 'name',
source: users.ttAdapter()
});

I had the same solution and discovered jQuery's cache: false; option does not work in this situation for whatever reason. Here is the solution I found:
remote: {
url: ...
replace: function(url, query) {
return url + "#" + query; // used to prevent the data from being cached. New requests aren't made without this (cache: false setting in ajax settings doesn't work)
}
}

try this:
remote: {
url: 'fake.jsp/?' + Math.random(),
.
.
.
it's not really the solution but at least the results will be fetched from server everytime the page is refreshed.

Related

Latest Chrome caching ajax response despite no cache headers

I have a simple form in a modal that gets populated by a ajax request (to a server running Django)
If I add choices to a choice field, those choices are not displaying for a few minutes on the modal. This issues only appeared after updating to the latest version of chrome (80.3987.149).
I am including no-cache headers in the ajax response like this:
response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
response['Pragma'] = 'no-cache'
response['Expires'] = '0'
But it doesn't seem to matter.
My ajax call method looks like this:
openAlertModalOnclick(e) {
e.preventDefault();
let self = this;
$.get($(e.target).attr("href"), resp => {
$("#alertModal").html(resp.html).foundation("open").foundation();
})
}).fail(() => {
this.showErrorToast("Error occurred while loading alerts.")
})
}
I am 90% sure this is an issue with just the latest version of chrome, as I could not reproduce it until I updated chrome. Is there anything else I can do to get chrome to stop caching the form?
The solution was the change the $.get call to $.ajax and pass in a cache: false parameter.
The function to open the modal now looks like this:
openForm52AlertModalOnclick(e) {
e.preventDefault();
let self = this;
SpinnerController.showSpinner();
$.ajax({
url: $(e.target).attr("href"),
method: 'GET',
cache: false,
success: function (resp) {
$("#alertModal").html(resp.html).foundation("open").foundation();
},
error: function () {
this.showErrorToast("Error occurred while loading alerts.")
},
});

Ember - Issue with HTTP POST request

I have written a (very) simple RESTFul Web service to retrieve data from MongoDB using Node, Express and Mongoose.
On the server side, I have this code:
router.route('/products').post(function(req,res){
var product = new Product(req.body);
product.save(function(err){
if(err)
res.send(err);
res.send({message:'Product Added'});
});
When I submit a request from my Ember client, the req.body contains something like the following:
{ attributes:
{ category: 1,
name: 'y',
price: 1,
active: false,
notes: null } }
The attribute names are exactly the same as my mongoose schema. I get no error but the document created in MongoDB is empty (just get the _id and __v fields).
What am I doing wrong. Should I convert the req.body further into ???
A couple things that will help debug:
1) From a quick glance (I haven't used mongoose before) it looks like call back function passed to save takes two arguments.
2) I don't know if your code got cut off, but the sample above was missing a matching });
3) I made the function short circuit itself on error, so you will not see 'Product added' unless that is truly the case.
Try these fixes.
router.route('/products').post(function(req,res){
var product = new Product(req.body);
product.save(function(err, product){
if(err){
return res.send(err);
}
return res.send({message:'Product Added'});
});
});
The issue was related to my lack of familiarity with Ember and Node+Express. The data received in the server is slightly different from what I had first indicated: (first line was missing)
{ product:
{ attributes:
{ category: ... } } }
On the server side I can access my data using req.body.product.attributes (instead of req.body):
router.route('/products').post(function(req,res){
var product = new Product(req.body.product.attributes);
product.save(function(err){
if(err)
res.send(err);
res.send({message:'Product Added'});
});

Parse Cloud Code with facebook API not working properly

I want to get a location Id from facebook API (that is already in my DB) and than use this to get the events from that location.
So, i'm first running a query to get this info and than adding this result as a parameter in my url. The fact is that the query is returning the result properly but when calling the httpRequest this is failling. Its important to say that my httpRequest works when I use the locationId hard coded.
I guess this problem is occuring because of the response calls but i cant figure out how to fix it. I'm also looking on a better way to design this code. Any ideas?
Parse.Cloud.define("hello", function(request, response) {
var query = new Parse.Query("Location");
query.find({
success: function(results) {
locationId = results[0].get("locationFbId");
console.log(locationId);
},
error: function() {
response.error("Failed on getting locationId");
}
});
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/'+locationId+'/events?access_token='+accessToken,
success: function(httpResponse) {
console.log(httpResponse.data);
response.success("result");
},
error:function(httpResponse){
console.error(httpResponse.message);
response.error("Failed to get events");
}
});
});
Adolfosrs, your problem here is that your two requests are running asynchronously on different threads. Therefore, your first request isn't returning until after your second request has been called. I would suggest chaining the requests as below so that your second request will be initialized with the data retrieved from the first request.
Parse.Cloud.define("hello", function(request, response) {
var query = new Parse.Query("Location");
query.find({
success: function(results) {
locationId = results[0].get("locationFbId");
console.log(locationId);
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/'+locationId+'/events?access_token='+accessToken,
success: function(httpResponse) {
console.log(httpResponse.data);
response.success("result");
},
error:function(httpResponse){
console.error(httpResponse.message);
response.error("Failed to get events");
}
});
},
error: function() {
response.error("Failed on getting locationId");
}
});
});

Incorrect base URL for Backbone DELETE requests - uses relative instead of absolute URLs

TL;DR version:
Building a Phonegap app using Backbone, and have a model called Client and a collection called Clients. Using a Tastypie API to communicate with a separate server. When I run fetch(), the URL uses the correct absolute URL (something like http://127.0.0.1:8000/api/v1/client/1/, but when I run Client.destroy(), it uses a relative URL of file:///api/v1/client/1/. How can I make it use the absolute URL for deleting the object?
Long version:
I'm building a mobile app with Backbone.js that consumes a Django/Tastypie API, and I've run into some seemingly odd behaviour that I can't figure out.
I define a base URL for the server at the top of the file:
// Set the base URL for querying the API
baseUrl = 'http://127.0.0.1:8000/api/v1/';
I have the following model and collection:
// Client model
Client = Backbone.Model.extend({
urlRoot: baseUrl + 'client',
// Default values
defaults: {
id: '',
name: '',
mobile: '',
email: '',
notes: '',
operator: '',
date_client_joined: '',
address: '',
postcode: ''
}
});
// Client collection
Clients = Backbone.Collection.extend({
// Will hold Client objects
model: Client,
// Set URL
url: baseUrl + 'client/'
});
And the individual clients are rendered in a list using the following view:
// Client list item view
ClientListItemView = Backbone.View.extend({
tagName: 'li',
events: {
'click .delete': 'deleteclient'
},
render: function () {
// Render the client list item template
var template = _.template($('#client-list-item-template').html());
this.$el.html(template(this.model.toJSON()));
// Return the object
return this;
},
deleteclient: function () {
this.model.destroy();
return false;
}
});
Now, the app actually uses jQuery Mobile and each client has a Delete button next to it with a class of delete, so the deleteclient function is executed each time one of these buttons is clicked. I'm also using backbone-tastypie to iron out the inconsistencies between Backbone and Tastypie.
The deleteclient function is running, but it sends the HTTP DELETE request to a relative URL of file:///api/v1/client/1/ (as this is a Phonegap app, I'm just viewing the files locally). From the documentation setting urlRoot manually seems like the way to go, but doing so didn't seem to solve the issue. Running the fetch() function to populate the collection works absolutely fine, though - it uses the correct absolute URL.
So, my question is how can I override the default behaviour and ensure my HTTP DELETE request is sent to the correct URL?
By looking at your code it should work ok. The Model in backbone already has a url() function defined which should do this:
url: function() {
var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
if (this.isNew()) return base;
return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
},
Can you use the debugger to see if it enters inside this code and what is the result of it? Mainly check the values from the _.result() calls...
Anyway, you can override the url property in your models rather than passing it in every call to destroy():
Client = Backbone.Model.extend({
url: function () { return baseUrl + 'client/' + this.id + '/'; }
// other code...
});
I found a solution, though I'm not entirely happy with it:
deleteclient: function () {
if (confirm('Are you sure you wish to delete this client?')) {
// Destroy the model
this.model.destroy({
url: baseUrl + 'client/' + this.model.get('id') + '/'
});
// Remove the view
this.remove();
}
}
Basically, if I explicitly pass through the URL to destroy(), that does the trick. It's a little annoying that I can't find a more DRY way to do this, so I'm open to any other method of doing the same thing.

Mobile Application Using Sencha Touch - JSON Request Generates Syntax Error

I started playing a bit with Sencha Touch.
So I've built a really simple application based on one of the examples just to see how it goes.
Basically it creates a JSON Request which executes a Last.FM web service to get music events near the user's location.
Here's the JSON code:
var makeJSONPRequest = function() {
Ext.util.JSONP.request({
url: 'http://ws.audioscrobbler.com/2.0/',
params: {
method: 'geo.getEvents',
location: 'São+Paulo+-+SP',
format: 'json',
callback: 'callback',
api_key: 'b25b959554ed76058ac220b7b2e0a026'
},
callback: function(result) {
var events = result.data.events;
if (events) {
var html = tpl.applyTemplate(events);
Ext.getCmp('content').update(html);
}
else {
alert('There was an error retrieving the events.');
}
Ext.getCmp('status').setTitle('Events in Sao Paulo, SP');
}
})
};
But every time I try to run it, I get the following exception:
Uncaught SyntaxError: Unexpected token :
Anyone has a clue?
A couple of things. First of all the "Uncaught SyntaxError: Unexpected token :" means the browser javascript engine is complaining about a colon ":" that has been put in the wrong place.
The problem will most likely be in the returned JSON. Since whatever the server returns will be run though the eval("{JSON HTTP RESULT}") function in javascript, the most likely thing is that your problem is in there somewhere.
I've put your code on a little sencha test harness and found a couple of problems with it.
First: My browser was not too happy with the "squiggly ã" in location: 'São+Paulo+-+SP', so I had to change this to location: 'Sao+Paulo,+Brazil', which worked and returned the correct results from the audioscribbler API.
Second: I notice you added a callback: 'callback', line to your request parameters, which changes the nature of the HTTP result and returns the JSON as follows:
callback({ // a function call "callback(" gets added here
"events":{
"event":[
{
"id":"1713341",
"title":"Skank",
"artists":{
"artist":"Skank",
"headliner":"Skank"
},
// blah blah more stuff
"#attr":{
"location":"Sao Paulo, Brazil",
"page":"1",
"totalpages":"1",
"total":"2"
}
}
}) // the object gets wrapped with extra parenthesis here
Instead of doing that I think you should be using the callbackKey: 'callback' that comes with the example in http://dev.sencha.com/deploy/touch/examples/ajax/index.js.
Something like this for example:
Ext.util.JSONP.request({
url: 'http://ws.audioscrobbler.com/2.0/',
params: {
method: 'geo.getEvents',
location: 'Sao+Paulo,+Brazil',
format: 'json',
api_key: 'b25b959554ed76058ac220b7b2e0a026'
},
callbackKey: 'callback',
callback: function(result) {
// Output result to console (Firebug/Chrome/Safari)
console.log(result);
// Handle error logic
if (result.error) {
alert(result.error)
return;
}
// Continue your code
var events = result.data.events;
// ...
}
});
That worked for me so hopefully it'll work for you too. Cherio.