jQuery autocomplete dynamic ajax - javascript

I'm trying to build a search input with the autocomplete feature. However, the suggestions depend on the input and are not static - which means that I have to retrieve the list every time the user types into the field. The suggestions are based on Google autosuggest: "http://google.com/complete/search?q=TERM&output=toolbar".
I'm currently using http://easyautocomplete.com.
This is my code:
var array = [];
var options = {
data: array
};
$("#basics").easyAutocomplete(options);
$("#basics").on("keyup",function() {
var keyword = $(this).val();
array = [];
updateSuggestions(keyword);
});
function updateSuggestions(keyword) {
$.ajax({
type: "POST",
url: "{{ path('suggestKeywords') }}",
data: {keyword:keyword},
success: function(res){
var res = JSON.parse(res);
for(var i in res)
{
var suggestion = res[i][0];
array.push(suggestion);
console.log(suggestion);
}
}
});
var options = {
data: array
};
$("#basics").easyAutocomplete(options);
}
I know this is not a very good way to do this - so do you have any suggestions as to how to do it?

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Autocomplete functionality</title>
<link href="http://code.jquery.com/ui/1.10.4/themes/ui-lightness/jquery-ui.css" rel="stylesheet">
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<!-- Javascript -->
<script>
$(function() {
var availableTutorials = [
"ActionScript",
"Boostrap",
"C",
"C++",
];
$("#automplete-1").autocomplete({
source: availableTutorials
});
});
</script>
</head>
<body>
<!-- HTML -->
<div class="ui-widget">
<p>Type "a" or "s"</p>
<label for="automplete-1">Tags:</label>
<input id="automplete-1">
</div>
</body>
</html>

Related

Creating an autocomplete function in Google script that works with a list of values from the Google Sheet

I'm trying to create an autocomplete text field, that autocompletes the country that's filled in, if the country already exists in the google sheet. At the moment my code only works, when I write all the possible countries in the 'availabletags' variable. But I want it to get the values directly from the google sheet. This is the html & script:
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<div class="ui-widget">
<label for="text">country</label>
<input id="text">
</div>
<div>
<button id="btn"> Run it! </button>
</div>
<script>
$(function() {
var availableTags = [ //should be changed to availableTags = list;
"belgium",
"france",
"greece",
"spain",
"italy",
"the netherlands"
];
$("#text").autocomplete({
source: availableTags
});
});
document.getElementById("btn").addEventListener("click", doStuff);
function doStuff() {
var ucountry = document.getElementById("text").value;
google.script.run.userClicked(ucountry);
document.getElementById("text").value = "";
};
</script>
</body>
</html>
I wrote following code in google script to retrieve the countries from the google script, and when I look at the log, the list of countries from the google sheet is indeed in the list variable.
function doGet() {
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data");
var list = ws.getRange(1,1,ws.getRange("A1").getDataRegion().getLastRow(),1).getValues(); // contains countries
Logger.log(list);
var template = HtmlService.createTemplateFromFile("page");
template.list = list.map(function(r){return r[0]; });
var html = template.evaluate();
return html;
}
function userClicked(country){
var url = "https://docs.google.com/spreadsheets/d/1IMxZwN3swMTf9EoF_k3iRV7Zc6iwzoWzov5-qC_MSKU/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Data");
ws.appendRow([country]);
}
I would like to have the var availableTags = list; But when I do that, the autocomplete stops working. Any help would be appreciated!
Use google.script.run with SuccessHandler
This implies the creation of an additional .gs function that will be called from clientside onload.
Sample:
Code.gs
function doGet() {
var template = HtmlService.createTemplateFromFile("page");
var html = template.evaluate();
return html;
}
function getCountry(){
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data");
var list = ws.getRange(1,1,ws.getRange("A1").getDataRegion().getLastRow(),1).getValues(); // contains countries
list = list.map(function(r){return r[0]; });
Logger.log(list);
return list;
}
function userClicked(country){
var url = "https://docs.google.com/spreadsheets/d/1IMxZwN3swMTf9EoF_k3iRV7Zc6iwzoWzov5-qC_MSKU/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Data");
ws.appendRow([country]);
}
page.html
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>
<div class="ui-widget">
<label for="text">country</label>
<input id="text">
</div>
<div>
<button id="btn"> Run it! </button>
</div>
<script>
google.script.run.withSuccessHandler(tags).getCountry();
function tags(list) {
console.log(list);
var availableTags = list;
$("#text").autocomplete({
source: availableTags
});
};
document.getElementById("btn").addEventListener("click", doStuff);
function doStuff() {
var ucountry = document.getElementById("text").value;
google.script.run.userClicked(ucountry);
document.getElementById("text").value = "";
};
</script>
</body>
</html>

Any Event Listener

Are there any Event Listeners that can be attached to a word. So when the word is clicked, information like a definition can be displayed on the page. Using jQuery
Thanks,
Adam
Sorry for not posting code. I have to make it so that when the user clicks on the name of a person in the list, the box of data on the right side of the screen fills with the description of the location of the artwork. Which is in my JSON file.
Here is my code so far
<!DOCTYPE html>
<hmtl lang="en">
<head>
<meta charset="utf-8" />
<title>AJAX</title>
<link rel="stylesheet" href="styles.css" type="text/css" />
<script src="jquery.js" type="application/javascript"></script>
<script src="ajax.js" type="application/javascript"></script>
</head>
<body>
<div id="loaded-data"></div>
<div id="result-box"></div>
</body>
</hmtl>
$(function() {
let request = $.ajax({
method: 'GET',
url : 'people.json',
dataType: 'json',
});
request.done(function(data) {
let list = data.body.list;
let resultBox = $('#result-box');
let unorderedList = $('<ul>');
resultBox.append(unorderedList);
for (let person of list) {
let listItem = $('<li>');
listItem.text(person.name);
listItem.attr('data-url', person.links[0].href);
unorderedList.append(listItem);
}
});
request.fail(function(response) {
console.log('ERROR: ' + response.statusText);
});
});
{
"links":[{"rel":"self","href":"http://www.philart.net/api/people.json"},{"rel":"parent","href":"http://www.philart.net/api.json"}],
"head":{"title":"People","type":"listnav"},
"body":{
"list":[
{"name":"Adam","links":[{"rel":"self","href":"http://www.philart.net/api/people/325.json"}]},
{"name":"Abigail Adams","links":[{"rel":"self","href":"http://www.philart.net/api/people/157.json"}]},
{"name":"John Adams","links":[{"rel":"self","href":"http://www.philart.net/api/people/410.json"}]},
{"name":"Samuel Adams","links":[{"rel":"self","href":"http://www.philart.net/api/people/439.json"}]},
{"name":"Lin Zexu","links":[{"rel":"self","href":"http://www.philart.net/api/people/347.json"}]},
{"name":"James A. Zimble","links":[{"rel":"self","href":"http://www.philart.net/api/people/345.json"}]},
{"name":"Doris Zimmerman","links":[{"rel":"self","href":"http://www.philart.net/api/people/171.json"}]}
]
}
}
Teemu has already mentioned a way to accomplish this behavior in the comment. You can do it as follows
// handle click and add class
$(".word").click(function() {
var word = $(this).text()
alert(word);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<p class="word">Hello</p>
</div>
You could replace the word and wrap it with a div.
$('p').html(function(index, value) {
return value.replace(/\b(here)\b/g, '<div class ="event">here</div>');
});
$('.event').click(function() {
console.log('definition');
});
<p>This is the information: Click here.</p>

Why does this HTTP request return array lengths rather than content?

I am working on some stuff here that includes fetching data asynchronously from an API. All is well except when I try pushing the correct answer into the incorrect answers array. All that is being returned are the respective array lengths rather than the content. What is it that I am doing wrong?
Here are the HTML and jQuery codes:
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="index.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div>
<h3>Answers</h3>
<ol></ol>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="index.js"></script>
</body>
</html>
jQuery
$(() => {
$.ajax({
method: "GET",
url: "https://opentdb.com/api.php?amount=50&category=18",
async: true,
success: (data) => {
let results = data.results;
$.each(results, (i, difficulty, question) => {
difficulty = results[i].difficulty;
question = results[i].question;
correctAnswer = results[i].correct_answer;
answers = results[i].incorrect_answers;
$("ol").append(`
<li>${answers.push(correctAnswer)}</li>
`);
});
}
});
});
Check the docs for the push function.
Return value
The new length property of the object upon which the method was called.
Aat the end of your function you are pushing the correctAnswer to answers which returns the length of answers array and you are showing that in your html. That's perfectly natural.
Push first and then create the html tag.
Check this;
$(() => {
$.ajax({
method: "GET",
url: "https://opentdb.com/api.php?amount=50&category=18",
async: true,
success: (data) => {
let results = data.results;
$.each(results, (i, difficulty, question) => {
difficulty = results[i].difficulty;
question = results[i].question;
correctAnswer = results[i].correct_answer;
answers = results[i].incorrect_answers;
answers.push(correctAnswer)
$("ol").append(`
<li>${correctAnswer}</li>
`);
});
}
});
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="index.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div>
<h3>Answers</h3>
<ol></ol>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="index.js"></script>
</body>
</html>

Knockout bindings are not updating

I'm playing around with an app that gets playlistItem data from the youtube api and lists all titles in the playlist on a page using knockout.js. I can get the list to load just fine, but I'm running into some issues while trying to add some extra functionality to the app.
Things I'm trying to add are a count of the total number of titles in the playlist and an input field that lets the user load another playlist. I currently can get neither to work.
Here's the app.js file:
// global variables
var ytResults=[];
var pageToken;
//var clipCount=ko.observable('');
var clipsDone=0;
var ytPlaylistID='PLpmQJ2D10iJx_GEYNZwAON38cluj0dNj4';
// function to create clip objects
var clip=function(data){
this.clipTitle=ko.observable(data.title);
};
function Model(){
var self=this;
//Create an observable array to store a list of clip objects
self.clipList=ko.observableArray([]);
self.clipCount=ko.observable('');
}
var model =new Model();
function ViewModel(){
var self = this;
self.errorMessage=ko.observable('');
self.loadPlaylist=ko.observable('');
errorHandling=function(){
self.errorMessage("Can't load the list and app");
};
fillList=function(){
for(i=0;i<ytResults.length;i++){
var clipData={
title: ytResults[i]
};
model.clipList.push(new clip(clipData));
};
};
var ytConnector=(function(){
var searchYtRequest=function(requestPayload, callback){
$.ajax({
url: requestPayload.url,
type: requestPayload.method,
}).done(function(data){
//console.log(data);
model.clipCount=data.pageInfo.totalResults;
ytResults.length=0;
for(i=0;i<data.items.length;i++){
ytResults=ytResults.concat(data.items[i].snippet.title);
};
fillList();
pageToken=data.nextPageToken;
clipsDone=clipsDone+50;
if(clipsDone<model.clipCount){
ytConnector.fetchDataFromYt();
};
}).fail(function(jqxhr, textStatus, error) {
// Let empty results set indicate problem with load.
// If there is no callback - there are no UI dependencies
self.errorMessage("Failed to load: " + textStatus + ", " + error);
}).always(function() {
typeof callback === 'function' && callback(ytResults);
});
};
// get playlist data from youtube
function fetchDataFromYt(){
if(pageToken!=null){
thisUrl='https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId='+ytPlaylistID+'&key=AIzaSyBFrCeUpPitoT6eOk_mq6Uza6etWtAH0oQ&pageToken='+pageToken;
}else{
thisUrl='https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId='+ytPlaylistID+'&key=AIzaSyBFrCeUpPitoT6eOk_mq6Uza6etWtAH0oQ';
};
var requestData = {
url: thisUrl,
method: 'GET',
};
searchYtRequest(requestData);
}return{
fetchDataFromYt: fetchDataFromYt,
};
})();
ytConnector.fetchDataFromYt();
thisPlaylist=function(){
ytPlaylistID=self.loadPlaylist();
console.log('playlist ID: '+ytPlaylistID);
};
}
ko.applyBindings(new ViewModel());
// PLpmQJ2D10iJzd1SPy7FlaaBFt07fhLSL3
Here's the html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Telex|Aldrich" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
<title>Youtube playlist</title>
</head>
<body>
<div class="container">
<div class="errorMsg" data-bind="text: errorMessage, visible: errorMessage">
</div>
<div class="form-holder">
<form data-bind="submit: thisPlaylist">
playlist ID: <input type="text" size="50" data-bind="value: loadPlaylist, valueUpdate: 'afterkeydown'">
<button type="submit" data-bind="enable: loadPlaylist().length>0">submit</button>
</form>
</div>
<div class="info-holder">
clips in playlist:<span data-bind="text: model.clipCount"></span>
</div>
<ul class="listDiv" data-bind="foreach: model.clipList">
<li data-bind="text: clipTitle">
</ul>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="js/lib/knockout-3.2.0.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js"></script>
<script src="js/oauth-1.0a.js"></script>
<script src="js/app.js"></script>
</body>
model.clipCound is an observable object, the way you are setting the value is incorrect.
model.clipCount=data.pageInfo.totalResults;
You need to change to this
model.clipCount(data.pageInfo.totalResults);

Correct way to append data into existing data table using ajax

Introduction
I am working with the functions where user search donor organizations by name.
Data loads in DataTable, paging enabled and works fine for the initial data load.
(Data load with initial call from jquery is about 100 records)
Lately, i have tried to implement the ajax method, which is suppose to load "next 100 records" and append to the existing records(now record reaches at 200 aprox).
Problem
Record loading on ajax call is loaded into datatable but displays this recent record on current page(no paging applied on it).
When user change the page to navigate between records, this recent record disappear.
I am just manipulating DOM elements, i think i have to pass it to datatable, yes?
Complete Code(just copy and paste whole code to test,cdn libs used)
<!DOCTYPE html>
<!--[if IE 8]> <html lang="en" class="ie8"> <![endif]-->
<!--[if IE 9]> <html lang="en" class="ie9"> <![endif]-->
<!--[if !IE]><!-->
<html lang="en">
<!--<![endif]-->
<head>
<title>Demo : Test</title>
<!-- Meta -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.9/css/jquery.dataTables.min.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-3">
<form>
<input type="text" id="searchParam" name="searchParm" placeholder="enter search param">
<br>
<input type="submit" value="Submit" onclick="searchDonors(document.getElementById('searchParam').value); return false;">
</form>
<br />
</div>
<div class="col-md-9">
<div id="demoApim"><table id="demoApi"><thead><tr><td>Organization Name</td><td>Address</td></tr></thead><tbody id="tBody"></tbody></table></div>
</div>
<div class="col-md-3" id="searchBtn"><input type="submit" value="Load Next 100 Records" onclick="loadNext(); return false;"></div>
</div>
</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/1.10.9/js/jquery.dataTables.min.js"></script>
<script type="text/javascript">
var count;
$('#searchBtn').hide();
$(document).ready(function () { $('table').hide();});
function searchDonors(searchParam) {
window.searchDonorsParam = searchParam;
count = 100;
var request = new XMLHttpRequest();
request.open("GET", "http://graphapi.firstgiving.com/v1/list/organization?q=organization_name:" + searchParam + "*%20AND%20country:US&&page_size=100&page=1", false);
request.send();
var xml = request.responseXML;
//$.each(xml, function (key, val) {
var oName = xml.getElementsByTagName("organization_name");
//console.log(oName);
var oAddress = xml.getElementsByTagName("address_line_1");
var counts = xml.getElementsByTagName("organization_name").length;
for (var i = 1; i < counts; i++) {
var html = [];
html.push('<tr><td>', oName[i].innerHTML)
html.push('</td><td>', oAddress[i].innerHTML)
html.push('</td></tr>')
$("#tBody").append(html.join(''));
}
$('#demoApi').DataTable();
$('table').show();
$('#searchBtn').show();
//});
//console.log(oName);
//console.log(oAddress);
}
function loadNext()
{
if (count = 100)
{
$.ajax({
url: "http://graphapi.firstgiving.com/v1/list/organization?q=organization_name:" + searchDonorsParam + "*%20AND%20country:US&&page_size=100&page=2",
method: "GET",
dataType: "xml",
success: function (xml) {
var xmlDoc = $.parseXML(xml),
$xml = $(xmlDoc);
console.log(xml.getElementsByTagName("organization_name"));
var oNameMore = xml.getElementsByTagName("organization_name");
var oAddressMore = xml.getElementsByTagName("address_line_1");
var countsNew = xml.getElementsByTagName("organization_name").length;
var html;
for (var i = 1; i < countsNew; i++) {
html = [];
html.push('<tr><td>', oNameMore[i].innerHTML)
html.push('</td><td>', oAddressMore[i].innerHTML)
html.push('</td></tr>')
$("#tBody").append(html.join(''));
}
},
error: function () {
console.log("call failled");
}
});
}
}
</script>
</body>
</html>
If someone have idea about that problem please let me know, any kind of help or reference will be appreciated.
"I think i have to pass it to datatable, yes?". Yes. The correct way is to go through the API. Without using the API, dataTables cannot be aware of whatever changes you have made to the underlying <table> and therefore your recent records disappear :
var table; //outside your function scopes
in searchDonors() :
table = $('#demoApi').DataTable();
in loadNext() use row.add() instead of injecting markup to <tbody> :
for (var i = 1; i < countsNew; i++) {
table.row.add([oNameMore[i].innerHTML, oAddressMore[i].innerHTML]);
}
table.draw();
yes ofc modify DOM its not enought for datatables, you need to use datatables function to access data, use this:
initialize the table:
var myTable = $('#demoApi').DataTable();
then
myTable.row.add( [oNameMore[i].innerHTML,oAddressMore[i].innerHTML] );
all the data are stored inside datables settings object,
updating the DOM don't change the current table settings so you will
lose you change after any table redraw ( search, change page, ecc.. )

Categories