YUI3 - DataTable Datasource Polling - javascript

Im new to YUI3; Im trying to poll a datasource every 10 seconds to refresh a datatable. But with the code below it says there is 'No Data To Display'... Sorry for the large amount of code...
YUI().use("datatable", "datasource-get", "datasource-jsonschema", "datatable-datasource", "datasource-polling", "datasource-function", function (Y) {
var url = "http://query.yahooapis.com/v1/public/yql?format=json" +
"&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys",
query = "&q=" + encodeURIComponent(
'select * from local.search ' +
'where zip = "94089" and query = "pizza"'),
dataSource,
table;
dataSource = new Y.DataSource.Get({ source: url });
dataSource.plug(Y.Plugin.DataSourceJSONSchema, {
schema: {
resultListLocator: "query.results.Result",
resultFields: [
"Title",
"Phone",
{
key: "Rating",
locator: "Rating.AverageRating",
parser: function (val) {
// YQL is returning "NaN" for unrated restaurants
return isNaN(val) ? -1 : +val;
}
}
]
}
});
intervalId = dataSource.setInterval(10000, {
request : query,
callback: {
success: function (e) {
table.datasource.load(e.response);
},
failure: function (e) {
}
}
});
table = new Y.DataTable({
columns: [
"Title",
"Phone",
{
key: "Rating",
formatter: function (o) {
if (o.value === -1) {
o.value = '(none)';
}
}
}
],
summary: "Pizza places near 98089",
caption: "Table with JSON data from YQL"
});
table.plug(Y.Plugin.DataTableDataSource, { datasource: dataSource });
// This line works (but it doesnt poll)
//table.datasource.load({ request: query });
table.render("#pizza");
});
The line I am not sure about is...
success: function (e) {
table.datasource.load(e.response);
},

The following should fit your needs: http://developer.yahoo.com/yui/examples/datatable/dt_polling.html

Related

Two Stage Autocomplete

I'm using jquery-ui to add autocomplete to an input field. I have essentially a two stage autocomplete that I'm trying to set up. Typing M will display an autocomplete of all options, selecting an option will enter that into the input EX: "machineName=", depending upon the first option selected, I then want to load a second autocomplete in the same field to show the values for that filter.
It works using static data, however the second autocomplete, is using API data so I have an AJAX call at the beginning of my script with a .then to chain together the creation of the autocomplete after the API has been hit, typing anything after machineName= results in nothing being displayed, however logging the value of the array I can see all the values in it.
var occupations = [{
value: "machineName=",
label: "machineName"
}, {
value: "ipAddress=",
label: "ipAddress"
},];
let machineNameAC = []
let switchTerm= [];
$.ajax({
url: '/api/data',
contentType: 'application/json',
dataType: 'json',
type: 'GET',
success: function(response){
console.log(response)
response.result.forEach((res) => {
machineNameAC.push(res.machineName)
console.log(machineNameAC)
})
}
}).then(() => {
$(function() {
function split(val) {
return val.split('=');
}
function extractLast(term) {
return split(term).pop();
}
$("#occupation").on("keydown", function(event) {
if (event.keyCode === $.ui.keyCode.TAB &&
$(this).autocomplete("instance").menu.active) {
event.preventDefault();
}
}).autocomplete({
minLength: 0,
source: function(request, response) {
var term = extractLast(request.term);
var results = [];
if (request.term.indexOf("=") > 0) {
var regE = /([^=]*)$/
if (request.term.endsWith('=')) {
console.log('term ',request.term)
switch (request.term){
case 'machineName=':
machineNameAC.forEach((machine)=>{
switchTerm.push(machine)
})
break;
}
}
console.log(switchTerm)
console.log(request.term)
if (parseInt(term) > 0) {
$.each(machineNameAC, function(k, v) {
console.log(k, v)
results.push(term + "" + v);
});
}
} else {
results = $.ui.autocomplete.filter(
occupations, request.term);
}
response(results);
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function(event, ui) {
var terms = split(this.value);
terms[0] = terms[0] + "=";
// remove the current input
terms.pop();
// add the selected item
terms.push(ui.item.value);
// add placeholder to get the comma-and-space at the end
terms.push("");
this.value = terms.join("");
return false;
}
});
});
})
Based on your code, your first stage determines if the user will look up a machine name versus an IP Address. Example:
machineName=descartes or ipAddress=192.168.1.112
The example data you provided was:
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
This data does not have a good relationship with the search in your initial code. I am assuming you have multiple items and you want to review the term against the title, yet this is not seen in your example. This is likely just sample data and does not represent your actual data. I must assume your data is more like:
[{
userId: 1001,
userName: "John Smith",
machineName: "jsmith-1",
ipAddress: "192.168.1.112",
siteLocation: "Shipping Bay 1"
}, {
userId: 1002,
userName: "Bettie Page",
machineName: "bpage-1",
ipAddress: "192.168.1.169",
siteLocation: "Champagne Room"
}];
If this is the case, you can forgo the prefix and make it a single state lookup that examines the term and identifies a machine name (words) versus an IP address (numbers and dots) and supplies the correct data. It's your choice to have it be two stage or single stage. You will need a filter function for both types, regardless.
Something like this:
function filterMachine(term, myData) {
var results = [];
$.each(myData, function(key, val) {
if (val.machineName.toLowerCase().indexOf(term.toLowerCase()) != -1) {
results.push($.extend(val, {
label: val.machineName,
value: val.machineName
});
}
});
return results;
}
function filterIp(term, myData) {
var results = [];
$.each(myData, function(key, val) {
if (val.ipAddress.indexOf(term) == 0) {
results.push($.eaxtend(val, {
label: val.ipAddress,
value: val.ipAddress
}));
}
});
return results;
}
It's not clear from your post what you are then doing with this data once a user Selects the item. Maybe filtering a table or updating a form. I do suggest using minLength option, something like 2. In this example, they might enter 192 or des and this should be enough to logically determin what they are seeking.
Single Stage Example: https://jsfiddle.net/Twisty/60a1eLwz/32/
Your code will be a bit different as I am using the Echo feature of Fiddle, it does not use GET. Instead you POST data and it echos it back to the request.
JavaScript
$(() => {
var sampleData = [{
userId: 1001,
userName: "John Smith",
machineName: "jsmith-1",
ipAddress: "192.168.1.112",
siteLocation: "Shipping Bay 1"
}, {
userId: 1002,
userName: "Bettie Page",
machineName: "bpage-1",
ipAddress: "192.168.1.169",
siteLocation: "Champagne Room"
}];
function filterMachine(term, myData) {
var results = [];
$.each(myData, function(key, val) {
if (val.machineName.toLowerCase().indexOf(term.toLowerCase()) != -1) {
results.push($.extend(val, {
label: val.machineName,
value: val.machineName
}));
}
});
return results;
}
var apiData;
function filterIp(term, myData) {
var results = [];
$.each(myData, function(key, val) {
if (val.ipAddress.indexOf(term) == 0) {
results.push($.extend(val, {
label: val.ipAddress,
value: val.ipAddress
}));
}
});
return results;
}
$.ajax({
url: '/echo/json',
dataType: 'json',
type: 'POST',
data: {
json: JSON.stringify(sampleData)
},
success: function(response) {
apiData = response;
console.log('API Data ', apiData);
$("#inputField").on("keydown", function(event) {
if (event.keyCode === $.ui.keyCode.TAB &&
$(this).autocomplete("instance").menu.active) {
event.preventDefault();
}
}).autocomplete({
minLength: 2,
source: function(request, response) {
if (isNaN(request.term.replace(".", ""))) {
response(filterMachine(request.term, apiData));
} else {
response(filterIp(request.term, apiData));
}
},
focus: function() {
return false;
},
select: function(event, ui) {
$("#results").empty();
$.each(ui.item, function(key, value) {
$("#results").append(key + ": " + value + "<br />");
})
return false;
}
});
}
});
});
This is more similar to your code, where it collects all the data up front and it's in a variable. You could also just call the JSON content in the source upon each request. The only benefit is if there are frequent changes to the data, you will catch more of them. If you pull all the data when the page loads, and the user sits on the page for 1 or 2 minutes, the data source could potentially be updated and the User will not get that new data.
In my opinion, this is a more friendly user interface, the User enters what they are looking for without having to search twice. They get suggests and pull up the result. With the Two Stage, they have to make an initial selection and then search. If you still want two stage, I suspect you can see where you would inject your prefix code again and then on the second stage pass the term to the correct function and append the specific detail you need as the result.
Two Stage Example: https://jsfiddle.net/Twisty/60a1eLwz/46/
JavaScript
$(() => {
var sampleData = [{
userId: 1001,
userName: "John Smith",
machineName: "jsmith-1",
ipAddress: "192.168.1.112",
siteLocation: "Shipping Bay 1"
}, {
userId: 1002,
userName: "Bettie Page",
machineName: "bpage-1",
ipAddress: "192.168.1.169",
siteLocation: "Champagne Room"
}];
function filterMachine(term, myData) {
var results = [];
$.each(myData, function(key, val) {
if (val.machineName.toLowerCase().indexOf(term.toLowerCase()) != -1) {
results.push($.extend(val, {
label: val.machineName,
value: val.machineName
}));
}
});
return results;
}
function filterIp(term, myData) {
var results = [];
$.each(myData, function(key, val) {
if (val.ipAddress.indexOf(term) == 0) {
results.push($.extend(val, {
label: val.ipAddress,
value: val.ipAddress
}));
}
});
return results;
}
$("#inputField").on("keydown", function(event) {
if (event.keyCode === $.ui.keyCode.TAB &&
$(this).autocomplete("instance").menu.active) {
event.preventDefault();
}
}).autocomplete({
minLength: 0,
source: function(request, response) {
if (request.term.length <= 2) {
response([{
label: "machineName",
value: "machineName="
}, {
label: "ipAddress",
value: "ipAddress="
}]);
} else {
var terms = request.term.split("=");
console.log(request.term, terms);
$.ajax({
url: '/echo/json',
dataType: 'json',
type: 'POST',
data: {
json: JSON.stringify(sampleData)
},
success: function(data) {
if (terms[0] == "machineName") {
response(filterMachine(terms[1], data));
} else {
response(filterIp(terms[1], data));
}
}
});
}
},
focus: function() {
return false;
},
select: function(event, ui) {
var terms = this.value.split("=");
terms[0] = terms[0] + "=";
// remove the current input
terms.pop();
// add the selected item
terms.push(ui.item.value);
// add placeholder to get the comma-and-space at the end
terms.push("");
this.value = terms.join("");
return false;
}
});
});

Fancy tree: How to call two endpoint according to result

I am using fancy tree in my application UI:
f_tree = $("#nodes_tree").fancytree({
extensions: ["table"],
table: {
indentation: 24,
nodeColumnIdx: 0
},
source: [
{
title: "/",
key: "jcr:root",
folder: true,
lazy: true,
}
],
lazyLoad: function (event, data) {
let node = data.node;
let path = buildPath(node);
if (path !== '/') {
data.result = {
url: 'http://localHost:8080/getDetails'
};
} else {
data.result = elasticResponse;
}
},
postProcess: function (event, data) {
if (data.response) {
data.result = data.response._paths;
}
},
renderColumns: function (event, data) {
let d = data.node.data,
$tdList = $(data.node.tr).find(">td");
if (d.attributes) {
//console.info(`step 333`);
$tdList.eq(1).text(d.attributes['title'])
}
}
});
I am not able to write condition, if "http://localHost:8080/getDetails/1234" will return {} blank json response instead of {"_paths":[{"title":"..."}]"} response then it should call another url i.e; "http://localHost:8087/getAnotherDetails/1234". Please let me know how I can achieve this in fancy tree.

Datatables server side processing with mongodb and javascript

Hi I'm having some major issues trying to understand how to datatables to work with server side processing. For some background I'm using a service call Gamesparks to create the backend for a videogame and inside this service they have an implementation of mongodb.
I have an endpoint that fetchs all my users and I can see them in my table but the issue is that I fetch all of them, how can I achieve a pagination?. In the documentation they state that we must put serverSide to true but is not working. I really have no idea on how to proceed I need help.
Gamesparks event to fetch all users
require("LeaderboardMethods");
var playerList = Spark.runtimeCollection("playerList").find({},{"_id":0});
var finalData = [];
while(playerList.hasNext()){
var current = playerList.next();
var playerStats = Spark.runtimeCollection("playerStatistics").findOne({
"playerId":current.playerId
});
var loadedPlayer = Spark.loadPlayer(current.playerId);
var score = getScore(current.playerId);
if(loadedPlayer === null){
var toReturn = {
"playerId": current.playerId,
"displayName": current.displayName,
"email": "DELETED",
"rank": current.rank,
"coins": "DELETED",
"ban": "DELETED",
"score": score
}
finalData.push(toReturn);
} else{
var coins = loadedPlayer.getBalance("COIN");
var toReturn = {
"playerId": current.playerId,
"displayName": current.displayName,
"email": current.email,
"rank":playerStats.rank,
"coins": coins,
"ban": playerStats.isBlocked,
"score":score
}
finalData.push(toReturn);
}
}
Spark.setScriptData("playerList",finalData);
Datatables call
App.getUsers = function(){
var bodyData = {
"#class": ".LogEventRequest",
"eventKey": "GET_PLAYER_DATA",
"playerId": "MY_ID"
}
var table = $('#table1').DataTable({
"dom": "<'row be-datatable-header'<'col-sm-4'l><'col-sm-4'B><'col-sm-4'f>>" +
"<'row be-datatable-body'<'col-sm-12'tr>>" +
"<'row be-datatable-footer'<'col-sm-5'i><'col-sm-7'p>>",
"buttons": [
{
text: 'Edit',
action: function (e, dt, node, config) {
var sel_row = table.rows({
selected: true
}).data();
if (sel_row.length != 0) {
window.location.href = "edit-user.html";
localStorage.setItem("editUser", JSON.stringify(sel_row[0]));
}
}
},
{
text: 'Create',
action: function (e, dt, node, config) {
window.location.href = "create-user.html";
}
},
{
text: 'Delete',
className: 'delete-btn',
action: function (e, dt, node, config) {
var filtered = table.rows({
filter: 'applied',
selected: true
}).data();
// Only open modal when are users selected
if(filtered.length != 0){
$("#proceed-delete").prop('disabled', true)
$("#mod-danger-delete").modal();
if(filtered.length != 1) {
$('#length-users').append(document.createTextNode(filtered.length + " users"));
} else {
$('#length-users').append(document.createTextNode(filtered.length + " user"));
}
$("#delete-confirmation").change(function () {
if ($("#delete-confirmation").val() === "DELETE"){
$("#proceed-delete").prop('disabled', false)
$('#proceed-delete').on('click', function () {
if (filtered.length === 1) {
deleteUserRequest(filtered[0]);
} else {
for (let index = 0; index < filtered.length; index++) {
deleteUserRequest(filtered[index])
}
}
});
}
});
}
}
}, 'selectAll', 'selectNone'
],
"paging":true,
"pageLength":50,
"serverSide":true,
"ajax": {
"data": function (d) {
return JSON.stringify(bodyData);
},
"contentType": "application/json; charset=utf-8",
"url": config.REQUEST_API + '/rs/' + config.API_CREDENTIAL_SERVER + '/' + config.API_SERVER_SECRET + '/LogEventRequest',
"type":"POST",
"dataSrc":function(json){
console.log(json);
$('#loading-row').removeClass('be-loading-active');
return json.scriptData.playerList
},
},
"columns": [
{
data: null,
defaultContent: "<td></td>",
className: 'select-checkbox'
},
{ data: "playerId"},
{ data: "displayName" },
{ data: "email" },
{ data: "score"},
{ data: "rank" },
{ data: "isBlocked" },
{ data: "coins" },
{
"data": null,
"defaultContent": "<button class='btn btn-space btn-primary' onclick='App.click()'>View more</button>"
}
],
"select": {
style: 'multi',
selector: 'td:first-child'
},
}).on('error.dt', function(e, settings, techNote, message){
var err = settings.jqXHR.responseJSON.error;
// GS err
if(err === "UNAUTHORIZED"){
location.href = "pages-login.html";
return true;
} else{
$('#error-container-dt').show();
console.log(message);
return true;
}
});
}
Quick peek into Gamesparks SDK and found this for example:
ListTransactionsRequest
dateFrom Optional date constraint to list transactions from
dateTo Optional date constraint to list transactions to
entryCount The number of items to return in a page (default=50)
include An optional filter that limits the transaction types returned
offset The offset (page number) to start from (default=0)
Now, for paging you need entryCount and offset. First is size of one page, default 50, you can change it. Server returns 'entryCount' no of records.
Offset is the starting record. For example, initial list (1st page) does have 50 records, clicking "Next" button will send request "offset: 51" to the server. And server reply records from 50 (offset) to 100 (offset + entryCount).
var bodyData = {
"#class": ".LogEventRequest",
"eventKey": "GET_PLAYER_DATA",
"playerId": "MY_ID",
"entryCount": entryCount, // you have to send it if you dont like the default value
"offset": offset // gets his value from "NEXT" or "PREV" button
}
Thats how paging works. I'm not able to give more detailed answer as I dont use Gamesparks myself. Hope it gives you least some directon.

Cannot access data from component method

I tried components methods in vue js. My code like this.
const Thread = Vue.component('threadpage', function(resolve) {
$.get('templates/thread.html').done(function(template) {
resolve({
template: template,
data: function() {
return {
data: {
title: "Data Table",
count: this.GetData
}
};
},
methods: {
GetData: function() {
var data = {
username : "newshubid",
data : {
page : 0,
length : 10,
schedule : "desc"
}
};
var args = {"data" : JSON.stringify(data)};
var params = $.param(args);
var url = "http://example-url";
var result;
DoXhr(url, params, function(response){
result = JSON.parse(response).data;
console.log("load 1", result);
});
setTimeout(function () {
console.log("load 2", result);
return result;
}, 1000);
}
},
created: function(){
this.GetData();
}
});
});
});
But, when I trying to use {{ data.count }} in template. Not showing result what i want. Even I tried return result in GetData.
Whats my problem ? And how to access data from methods ? Please help me, i'm a beginner. Thanks
See the edited code and comments I added below.
You tried to return the result by using return in the function from setTimeout, which won't help you return value from GetData.
Instead, You can just set the value in the callback function of your ajax request.
const Thread = Vue.component('threadpage', function(resolve) {
$.get('templates/thread.html').done(function(template) {
resolve({
template: template,
data: function() {
return {
data: {
title: "Data Table",
// NOTE just set an init value to count, it will be refreshed when the function in "created" invoked.
count: /* this.GetData */ {}
}
};
},
methods: {
GetData: function() {
var data = {
username : "newshubid",
data : {
page : 0,
length : 10,
schedule : "desc"
}
};
var args = {"data" : JSON.stringify(data)};
var params = $.param(args);
var url = "http://example-url";
var result;
var vm = this;
DoXhr(url, params, function(response){
result = JSON.parse(response).data;
// NOTE set data.count to responsed result in callback function directly.
vm.data.count = result;
});
// NOTE I think you don't need code below anymore.
// setTimeout(function () {
// console.log("load 2", result);
// return result;
// }, 1000);
}
},
created: function(){
this.GetData();
}
});
});
});

How do I generate a treeView based on remote data using Kendo UI TreeView?

I have been reading ALL of the documentation on this and I still cannot get it to work.
I have a Web API which provides a JSON object. It's a list of 22 things. Just 22 lines of text.
I want to take these and form a TreeView. Each of these 22 strings will have items under them but I just want to get the first part working.
My first question is, how do I extract data from an API and populate a treeView with it?
On my main page, I have this:
<div id="treeView"></div>
On my JavaScript file I have this:
$("#treeView").kendoTreeView({
checkboxes: true,
dataSource: {
transport: {
read: {
url: "http://...",
dataType: "json"
}
}
}
});
When I try to run the page, I get "Request failed." [Retry]
If I open up a browser and go to this URL, data is returned fine as a JSON object.
What am I doing wrong here?
EDIT -
Code that is returning the JSON:
public List<string> getNotificationByUser(int id)
{
List<string> notificationTitles = new List<string>();
foreach (var notification in notifications)
{
notificationTitles.Add(notification.ToString());
}
return notificationTitles;
}
Ok! I've been able to reproduce your error. The question is that 22 lines of text are not a valid JSON.
Returning something like:
This
is
a
test
Is not a valid JSON.
But a valid JSON is not enough, you should return something like this:
[
{ "text": "This" },
{ "text": "is" },
{ "text": "a" },
{ "text": "test" }
]
I.e.: The result should be an array of objects where each object has a text field.
NOTE I know that it does not have to be called text but for simplicity I used it since it is the default value.
I figured out all of my answers:
function CreateNotificationTree(userId)
{
debugger;
var data = new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: "../api/notifications/byuserid/" + userId,
contentType: "application/json"
}
},
schema: {
model: {
children: "notifications"
}
}
});
$("#treeview").kendoTreeView({
dataSource: data,
loadOnDemand: true,
dataUrlField: "LinksTo",
checkboxes: {
checkChildren: true
},
dataTextField: ["notificationType", "NotificationDesc"],
select: treeviewSelect
});
function treeviewSelect(e)
{
var node = this.dataItem(e.node);
window.open(node.NotificationLink, "_self");
}
}
[HttpGet]
public List<Node> getNotifications(int id)
{
var bo = new HomeBO();
var list = bo.GetNotificationsForUser(id);
var notificationTreeNodes = (from GBLNotifications n in list
where n.NotificationCount != 0
select new NotificationTreeNode(n)).ToList();
var li = notificationTreeNodes.Select(no => new Node
{
notificationType = no.NotificationNode.NotificationType + " " + "(" + no.NotificationNode.NotificationCount + ")", notifications = bo.GetNotificationsForUser(id, no.NotificationNode.NotificationTypeId).Cast<GBLNotifications>().Select(item => new Notification
{
ID = item.NotificationId, NotificationDesc = item.NotificationDescription, Params = new List<NotificationParam>
{
new NotificationParam
{
ParamName = item.Param1, ParamVal = item.ParamValue1
},
new NotificationParam
{
ParamName = item.Param2, ParamVal = item.ParamValue2
},
new NotificationParam
{
ParamName = item.Param3, ParamVal = item.ParamValue3
},
new NotificationParam
{
ParamName = item.Param4, ParamVal = item.ParamValue4
},
new NotificationParam
{
ParamName = item.Param5, ParamVal = item.ParamValue5
},
},
ActionPageName = item.ActionPageName
}).ToList()
}).ToList();
li.ForEach(i => i.notifications.ForEach(x => x.SetNotificationLink()));
return li;
}

Categories