I am having trouble implementing the Twitter Bootstrap Typeahead feature with a JSON web Service.
I have looked at all the examples on this website and can't find anything that will work. I know my JSON web service works; I can enter the address in my browser and it returns the JSON I expect with the MIME type set to "application/json".
I have this JavaScript in the
<body>
of my HTML page:
<script>
$('#typeahead').typeahead({
source: function (query, process) {
return $.getJSON(
'http://localhost:8732/IngredientsService/search/',
{ query: query },
function (data) {
return process(data);
});
}
});
</script>
I have this code as my "input":
<input type='text' id='typeahead' class='typeahead' data-provide="typeahead" data-items="10" />
Can anyone explain why this is not working?
According to the last comment ("web service not being accessed") - have you tried the more normal / documented approach?
$('#typeahead').typeahead({
source: function (query, process) {
return $.get('http://localhost:8732/IngredientsService/search/', { query: query }, function (data) {
return process(data.options); //if JSON is [ "options" : { ...}
});
}
});
$.getJSON is not nessecary, but useful when you want to load an entire JSON and inject potion of it as a source for the typeahead
$.getJSON("http://localhost:8732/IngredientsService/search/", function(json) {
$("#typeahead").typeahead({
source : json.options //again, dont know the structure of the JSON
});
});
From what I can see from the typeahead documentation, the source key in the parameters object is not valid.
It should look more like this I think:
$('#typeahead').typeahead({
remote: 'http://localhost:8732/IngredientsService/search/q=%QUERY'
});
http://jsfiddle.net/qVjsu/
It's better to omit return when using async sources because process() will be triggered twice
$('#typeahead').typeahead({
source: function (query, process) {
$.getJSON('/search/json/'+ query), function (data) {
return process(data);
});
},
minLength: 1,
items: 8
});
Related
I'm trying to use Vuejs 2 to call an endpoint API multiple times until all data is retrieved.
I'm using the SharePoint REST api and the results come back in an object res.d.results, however I can only query 5000 items at a time.
If rest.d.__next exists, it also has the endpoint to the next batch of data.
When I run this code I can see in the chrome debugger that the second call is made but the data is never pushed to the table and I get this message in the browser console
Event.path is deprecated and will be removed. Please use Event.composedPath() instead.
new Vue ({
el:"#app",
data: {
test: "this is my test",
pg:[]
},
created: function(){
console.log("working");
this.loopData("https://srvsharepoint1p/sites/tactical_squad/ArhivaTool/_api/web/lists/getbytitle('Dosare')/items?$top=1000", this);
},
methods: {
getListData: function(url,that){ // function that calls the api
console.log("getting data");
var headers={
"Accept": "application/json;odata=verbose"
}
return $.ajax({
url:url,
type: "GET",
headers: headers,
success: function(data){
lData = data;
}
});
},
loopData: function (web){ // function to loop through API calls until all data is retrieved.
this.getListData(web).then(res => {
console.log(res);
this.pg.push(...res.d.results)
if (res.d.__next) { // if there is a next page do another api call
this.getListData(res.d.__next); // try to call the api again
} else {
console.log('aborted')
}
})
}
}})
Any help would be greatly appreciated
I managed to figure it out
It seems I was doing recursion wrong. Hope this helps someone else it's using axios now to get data instead of ajax
new Vue ({
el:"#app",
data: {
test: "this is my test",
pg:[], // table data
counter:0
},
created: function(){
console.log("working");
this.getListData("https://srvsharepoint1p/sites/tactical_squad/ArhivaTool/_api/web/lists/getbytitle('Dosare')/items?$top=5000" ); //endpoint
},
methods: {
getListData: function(url){ //recursive function that calls itself untill all data is retreived
var vm = this
console.log("getting data");
axios.get(url).then(function(res){
if (res.data["odata.nextLink"] ) { // check if another page needs to be requested
vm.pg.push(...res.data.value); // push values into table object
vm.getListData(res.data["odata.nextLink"]); //call function again
}
else {
console.log('aborted');
alert("Tabelul este incarcat, se poata folosi butonul de exprot")
}
})
.catch(function(error){
alert(error);
})
}})
I have an Odata result like this
{"odata.metadata":"https://localhost/DocTalkMobileWebApiOData/odata/$metadata#MasterPatient/#Element","PatUniqueId":"39e713db-6a0e-4e59-bf7b-033f4fc47ad5", "PatID":null,
"pat_lname":"White","pat_fname":"Peter","pat_mi":" ","pat_ssn":"270787655","pat_dob":"08/07/1973","pat_sex":"M","pat_status":null,"priInsID":2,"secInsID":1,"PCPID":1,"InternalDrID":1,"EXPID":1,"EXPDate":"","pat_phone":null,"isNew":true,"imported":true,"byWhom":"dt","lastUpdate":"2011-03-30T09:41:57.36","changeStamp":"AAAAAAAAIUE=","address":"","city":"","state":"","zip":"","currentMcp":"","currentVisitCount":-2,"otherId":"543674","pcpName":null,"hasChanges":true,"ProgramSource":null,"mrnID":"","createdBy":null,"createdDate":"2007-10-26T10:16:15","expLocation":null,"ethnicId":1,"prefLanguageId":1,"raceId":1
}
and i tried to get this result via kendo.ui.datasource:
newPatient = new kendo.data.DataSource({
type: 'odata', // <-- Include OData style params on query string.
transport: {
read: {
url: url + '/MasterPatient(guid\'00000000-0000-0000-0000-000000000000\')', // <-- Get data from here
dataType: "json" // <-- The default was "jsonp"
},
parameterMap: function (options, type) {
var paramMap = kendo.data.transports.odata.parameterMap(options);
delete paramMap.$inlinecount; // <-- remove inlinecount parameter.
delete paramMap.$format; // <-- remove format parameter.
return paramMap;
}
},
schema: {
data: function (data) {
return data;
},
total: function (data) {
return data['odata.count']
},
}
});
newPatient.fetch(function () {
kendo.bind($('#newPatientTab'), newPatient);
});
But not sure why it always throw error :
Uncaught TypeError: Object [object global] has no method 'slice'
Please help me. Thanks
In Kendo UI, DataSource works only with arrays. If you can change the server response to send something like this
[{"odata.metadata":"https://localhost/DocTalkMobileWebApiOData/odata/$metadata#MasterPatient/#Element","PatUniqueId":"39e713db-6a0e-4e59-bf7b-033f4fc47ad5","PatID":null,"pat_lname":"White","pat_fname":"Peter","pat_mi":" ","pat_ssn":"270787655","pat_dob":"08/07/1973","pat_sex":"M","pat_status":null,"priInsID":2,"secInsID":1,"PCPID":1,"InternalDrID":1,"EXPID":1,"EXPDate":"","pat_phone":null,"isNew":true,"imported":true,"byWhom":"dt","lastUpdate":"2011-03-30T09:41:57.36","changeStamp":"AAAAAAAAIUE=","address":"","city":"","state":"","zip":"","currentMcp":"","currentVisitCount":-2,"otherId":"543674","pcpName":null,"hasChanges":true,"ProgramSource":null,"mrnID":"","createdBy":null,"createdDate":"2007-10-26T10:16:15","expLocation":null,"ethnicId":1,"prefLanguageId":1,"raceId":1}]
then it will work fine.
N.B. It's in array format.
OR
You can wrap the single object into array on the client side, inside data function of the schema.
schema: {
data: function(server-response) {
return [server-response];
}
}
The Kendo team should put more time on good Documentation.
That means you are not using an odata source from the backed. You need to think about here do you really need a kendo odata source from the client in this case if your back-end not supported odata correcly.
See this response from odata url, http://services.odata.org/Northwind/Northwind.svc/?$format=json
It should return an array of object in the value field.
If you can't change the backed what you can do is to format the data in the Schema.data function
schema: {
data: function (data) {
return [data];
},
I created an .getjson() call to work with reddit.com's API. The code is below.
$(document).ready(function() {
var SEARCH_URL = 'http://www.reddit.com/r/subreddits/search.json?jsonp=?';
var searchQueryText = 'XBox'; //getSearchQueryText();
$.getJSON(SEARCH_URL, {
q: searchQueryText,
limit: 3
})
.done(function (data) {
$.each(data.data.children, function(i,item) {
$("<h1>").attr("src", item.data.url).appendTo("#images");
});
})
.fail(function (data) {
alert("Something went wrong");
});
});//end ready
My .getJSON() function works and gets back data. However I am having trouble with my .each() function. I know it's slightly off even though my console isn't giving me an error message. I was hoping someone much smarter than me could help me rewrite it so it passes the content through #images in my body?
The JSON looks like this
http://www.reddit.com/r/subreddits/search.json?q=xbox&limit=3
If you just want to show all URLs in the #images elements, there is some problem in your code.
I test the reddit JSON data you're fetching.
The URL is a web page link not a image resource.
So why you try to add a non-exist attribute "src" to h1 element?
Try to use text() if you just want to show the URL and append them to element:
var SEARCH_URL = 'http://www.reddit.com/r/subreddits/search.json?jsonp=?';
var searchQueryText = 'XBox'; //getSearchQueryText();
$.getJSON(SEARCH_URL, {
q: searchQueryText,
limit: 3
})
.done(function (data) {
$.each(data.data.children, function(i,item) {
$("<h1>").text(item.data.url).appendTo("#images");
});
})
.fail(function (data) {
alert("Something went wrong");
});
This is jsfiddle demo
Hope this is helpful for you.
This example of using jquery-ui autocomplete with a remote web service has a nice concise syntax:
$( "#birds" ).autocomplete({
source: "search.php",
minLength: 2
});
Here search.php returns an array as follows:
[
{ "id": "Passer domesticus", "label": "House Sparrow", "value": "House Sparrow" },
...
]
I want to use a WCF web service, but the same syntax doesn't work because the array returned is wrapped in a 'd' container object:
{"d":
[
{ "id": "Passer domesticus", "label": "House Sparrow", "value": "House Sparrow" },
...
]
}
Of course I can get round this by writing code to look into the "d" container, something like the following (untested - could have typos):
$( "#birds" ).autocomplete({
minLength: 2
source: function (request, response) {
$.getJSON("search.svc/GetBirds", request, function (data, status, xhr) {
if (status == "success") response(data.d);
}
}
});
Is this the best I can do or is there some more concise syntax?
Ideally I'd like to be able to specify "source" as a url and have it work with responses that are returned with or without the "d" container.
In my mind you have two options.
The first is to create a helper function that will map the results for you. This is probably the best/easiest solution. Simple code:
$( "#birds" ).autocomplete({
minLength: 2
source: function (request, response) {
$.getJSON("search.svc/GetBirds", request, function (data, status, xhr) {
if (status == "success")
handleResponse(data); //you write this function
}
}
});
The second option is you can "monkeypatch" the AutoComplete plugin functions to override the default behavior.
So in your case you want to override the $.ui.autocomplete.prototype._initSource function. Fair warning here that you are basically overriding a core function in the UI library and if that library is ever updated your function will always override it.
// Create a closure so that we can define intermediary
// method pointers that don't collide with other items
// in the global name space.
function monkeyPatchAutocomplete() {
// don't really need this, but in case I did, I could store it and chain
var oldFn = $.ui.autocomplete.prototype._renderItem;
var requestIndex = 0;
$.ui.autocomplete.prototype._initSource = function() {
// whatever
console.log("Override method");
var self = this,
array, url;
if ($.isArray(this.options.source)) {
array = this.options.source;
this.source = function(request, response) {
response($.ui.autocomplete.filter(array, request.term));
};
} else if (typeof this.options.source === "string") {
url = this.options.source;
this.source = function(request, response) {
if (self.xhr) {
self.xhr.abort();
}
self.xhr = $.ajax({
url: url,
data: request,
dataType: "json",
autocompleteRequest: ++requestIndex,
success: function(data, status) {
console.log("Override success function, handling request");
if (this.autocompleteRequest === requestIndex) {
response(data); //you handle both types of data here
}
},
error: function() {
console.log("Override error function, handling request");
if (this.autocompleteRequest === requestIndex) {
response([]);
}
}
});
};
} else {
this.source = this.options.source;
}
};
}
// When DOM is ready, initialize.
$(document).ready(function() {
monkeyPatchAutocomplete();
$("#birds").autocomplete({
source: "http://jqueryui.com/demos/autocomplete/search.php",
minLength: 2
});
});
Then your code doesn't need to execute anything different, it just handles the differences and passes it along to the success method.
Here is a jsFiddle for this: http://jsfiddle.net/lemkepf/DAQ6s/5/ Note: the actual autocomplete wont work as the cross domain security is in place. You can open up firebug and see the console.debug lines fire when you start typing in the box.
I have the following code snippet:
$(document).ready(function () {
// bind 'regFormBody' and provide a simple callback function
$('#regFormBody').ajaxForm(function() {
alert("Thank you for your comment!");
});
// validate the #regFormBody form when it is submitted
$("#regFormBody").validate({
submitHandler: function(form) {
alert('form is submitted');
},
rules: {
...
},
messages: {
...
}
});
}
The problem is that after I add the
// bind 'regFormBody' and provide a simple callback function
$('#regFormBody').ajaxForm(function() {
alert("Thank you for your comment!");
});
The form validation doesn't work at all. I always see the message alert('form is submitted') even without entering any information to form.
May you tell me how to solve this problem?
Thank you
You can expand your options object for .ajaxForm(), like this:
$('#regFormBody').ajaxForm({
beforeSubmit: function() {
return $('#regFormBody').valid();
},
success: function() {
alert('Thanks for your comment!');
}
});
This will kick off validation before submitting, and if it's not .valid() it'll stop the submit from happening like you want.