jsTree - Populate Tree Dynamically using AJAX/C#Web Method - javascript

I have a div which I would like to fill with a jsTree:
I get the "Loading" icon where the tree is meant to display, however, there would seem to be a javascript error, even though one is not thrown.
I load my folder structure from an AJAX Request as follows. The Documents.aspx/GetFolders Web Method returns a List containing FolderId, ParentId & Folder Name. I have debugged the web method and it is passing the correct results to the jsTree "data" function.
$.ajax({
type: "POST",
url: 'Documents.aspx/GetFolders',
contentType: "application/json; charset=utf-8",
success: function (data) {
data = data.d;
$("#tree").jstree({
"core": {
"themes": {
"responsive": true
},
"data": function () {
var items = [];
items.push({ 'id': "jstree_0", 'parent': "#", 'text': "Documents" });
$(data).each(function () {
items.push({ 'id': "jstree_" + this.DocumentFolderId, 'parent': "jstree_" + this.ParentId, 'text': "" + this.Name });
});
return items;
}
},
"types": {
"default": {
"icon": "fa fa-folder icon-lg"
},
},
"plugins": ["contextmenu", "dnd", "state", "types"]
});
},
error: function () {
toastr.error('Error', 'Failed to load folders<span class=\"errorText\"><br/>There was a fatal error. Please contact support</span>');
}
});
After debugging the code, it seems the data is being retrieved correctly and is returning the object array as intended.
Is there are any problem with the above (or is there somewhere else I should be looking)? Or is there a better method of achieving its intended purpose?

I think I have finally found the answer! :)
"core": {
"themes": {
"responsive": true
},
"data": {
type: "POST",
url: "Documents.aspx/GetFolders",
contentType: "application/json; charset=utf-8",
success: function (data) {
data.d;
$(data).each(function () {
return { "id": this.id };
});
}
},
}
Server side, you need to return the data in the array format required, i.e:
[{id = "node0", parent = "#", text = "Documents"},
{id = "node1", parent = "node0", text = "Public"},
{id = "node2", parent = "node0", text = "Restricted"}]

Just in case anyone has the "loading..." issue, this format fixed it for me when returning data.
[{"id":"node0", "parent":"#", "text":"Documents"},
{"id":"node1", "parent":"node0", "text":"Public"},
{"id":"node2", "parent":"node0", "text":"Public"}]

Related

JQuery DataTables Columns Initializing automatically with data

I have a JQuery DataTable and I have been using it for a while, I guess I am missing something here.
However I came into one of the requirement recently to directly bind with JSON Data.
My JSON for example looks like i.e. coming from API :
[{"componentNumber":"ABC","factory":"India","productNumber":"CR","productRevisionState":"123","placementTimeLocal":"2018-08-21T00:00:00","position":"up"},{"componentNumber":"ABC","factory":"India","productNumber":"CR","productRevisionState":"123","placementTimeLocal":"2018-08-21T00:00:00","position":"up"},
{"componentNumber":"ABC","factory":"India","productNumber":"CR","productRevisionState":"123","placementTimeLocal":"2018-08-21T00:00:00","position":"up"}]
I know that I can use JSON and take columns out in Jquery and pass it to the Datatables columns but what I am looking if there is a simple way where Datatable takes column automatically something like:
$.ajax({
type: "Post",
url: "http://localhost:5555/myapi",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
//datasource = data;
$('#myTable').DataTable({
"Data": JSON.parse(data),
"Columns" : JSON.parse(data)
});
},
error: function (err) {
alert(err);
}
})
What I am looking is that:
Does JQuery have any such features or not? If not can you suggest
any other Datatable library which is fast for large dataset.
I want to get rid of all extra looping around the code
I can't update source system from where data is getting returned
Updated Version of Code, took from below answers, thanks Kiran for making me move a bit:
$.ajax({
type: "Post",
url: "http://localhost:5555/myapi",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
// **how to get rid of this loop? for looping columns**
var adColumns = [];
$.each(data[0], function (i, item) {
var col = {
data: i,
title: i
};
adColumns.push(col);
})
//datasource = data;
console.log(data);
$('#myTable').DataTable({
"data": data,
"info": true,
"paging": true,
"columns": adColumns
});
},
error: function (err) {
alert(err);
}
})
try the following code. It may help you to achieve the desired result. This may not be an optimized code.
Hope this helps.
EDIT
At least one loop will be required to create the array of column names.So you can also use the following code to eliminate multiple loops.
var adColumns = [];
Object.keys(strData[0]).forEach(key => {
var col = {
data: key,
title: key
};
adColumns.push(col);
});
$(function() {
var strData = [{
"componentNumber": "ABC",
"factory": "India",
"productNumber": "CR",
"productRevisionState": "123",
"placementTimeLocal": "2018-08-21T00:00:00",
"position": "up"
}, {
"componentNumber": "ABC",
"factory": "India",
"productNumber": "CR",
"productRevisionState": "123",
"placementTimeLocal": "2018-08-21T00:00:00",
"position": "up"
},
{
"componentNumber": "ABC",
"factory": "India",
"productNumber": "CR",
"productRevisionState": "123",
"placementTimeLocal": "2018-08-21T00:00:00",
"position": "up"
}
];
/*var dta = strData;
var tableColumnNames = [];
var keys = [];
for (var i in strData) {
var key = i;
var val = strData[i];
for (var j in val) {
var sub_key = j;
keys.push(sub_key);
}
}
var sColumns = Array.from(new Set(keys));
var adColumns = [];
for (var col in sColumns) {
var sKey = sColumns[col];
var col = {
data: sKey,
title: sKey
};
adColumns.push(col);
}*/
var adColumns = [];
Object.keys(strData[0]).forEach(key => {
var col = {
data: key,
title: key
};
adColumns.push(col);
});
$('#myTable').DataTable({
"data": strData,
"columns": JSON.parse(JSON.stringify(adColumns))
});
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/datatables/1.10.19/js/jquery.dataTables.min.js"></script>
<table id="myTable">
</table>
DataTables has the ability to read data from virtually any JSON data source that can be obtained by Ajax. This can be done, in its most simple form, by setting the ajax option to the address of the JSON data source. See This Link in DataTable Website.
As for your JSON, here is a fiddle

Use form naming to reach json data in Javascript/jQuery?

I have the following input name: dynamic[elements][1][slider][image1]
When performing an ajax call, a json response with settings and its value is returned.
$.ajax({
url: '/get/settings',
type: 'POST',
data: formData,
async: false,
success: function (data) {
});
How can i get the value of dynamic[elements][1][slider][image1] the easiest way? It works to get the value like this:
data.dynamic.elements[1].slider.image1
So:
$.ajax({
url: '/get/settings',
type: 'POST',
data: formData,
async: false,
success: function (data) {
console.log(data.dynamic.elements[1].slider.image1);
});
But isn't their any better way of getting the value? The only identifier I have to get the value, is the name of the input field which is dynamic[elements][1][slider][image1]. So i would need to extract this string and put it together as data.dynamic.elements[1].slider.image1 to then make it a dynamic variable somehow (to finally get the value)?
Example ajax response:
{
"success": 1,
"dynamic": {
"elements": [
{
"title": {
"title": "Our beautiful topic"
}
},
{
"slider": {
"image1": "5zw3ucypzp3qham.png",
"image1_link": "hellor"
}
}
]
}
}
You may choose to write a generic function for the purpose of retrieving data from object. The function should look something like below. Though the function may not be foolproof but should be enough for proof-of-concept.
function getObjectData(target, path) {
// if the path is not in dot notation first convert
if (path.indexOf(".") == -1)
path = path.replace(/\[/g, ".").replace(/\]/g, "");
var parts = path.split(".");
return parts.reduce(function (acc, currentVal) {
return acc ? (acc[currentVal] || undefined) : acc;
}, target);
}
//usage
getObjectData(data, "dynamic.elements.0.slider.image1"); //undefined
getObjectData(data, "dynamic.elements.1.slider.image1"); //5zw3ucypzp3qham.png
getObjectData(data, "dynamic[elements][1][slider][image1]"); //5zw3ucypzp3qham.png
Hope this helps.

Loop displaying undefined and I can't see where I've set it wrong

I'm looping through data from a .net web service through jsonp. Similar code works elsewhere but I can't see where i've gone wrong here.
The data is retreived through:
if (pageId === 'alerts') {
var Username = localStorage.getItem("Username");
var SessionKey = localStorage.getItem("SessionID");
console.log(Username);
console.log(SessionKey);
$.mobile.loading( 'show', { theme: "b", text: "Loading", textonly: false});
$.ajax({
crossDomain: true,
contentType: "application/json; charset=utf-8",
url: "http://redacted/GetData.asmx/GetLostAnimals",
data: {Username: Username, SessionKey: SessionKey },
dataType: "jsonp",
success: myAlerts
});
}
var lostSelectedPet = 0;
function myAlerts(data)
{
$("#alertsListMissingPets").empty();
$.mobile.loading( 'hide', { theme: "b", text: "Loading", textonly: false});
$.each(data, function(index) {
console.log(data[index].LostDate)
$("#alertsListMissingPets").append(" <li>"+ data[index].AnimalKey + " <span class=\"ui-li-count\">12</span></li>");
});
$("#alertsListMissingPets").listview('refresh');
}
$(document).on('click', '#alertsListMissingPets li a', function(){
localStorage.setItem("lostSelectedPet", $(this).attr('data-custom'));
editingId = $(this).attr('data-custom');
});
The json returned is like:
callback(
{
AnimalKey: "f152e1c6baca181d9f3ca1f18c91cc41f23fc122545d9c8bff9f4cb2ea449874",
LostDate: "11/06/2014 16:14:19",
FoundDate: "",
LostKey: "7560733274a7ca2ec43a85fcb9abd345fdc876acffac2b75ace7946035122fbd",
Resp: "OK"
}
)
However, this returns - It shows 5 items but theres only one result, the json above is the full response.
You are not looping over an array, you are looping over an object. You have 5 keys in the object, hence why there is 5 rows in the output.
Change the response to be an array.
callback(
[{ //<-- added [
AnimalKey: "f152e1c6baca181d9f3ca1f18c91cc41f23fc122545d9c8bff9f4cb2ea449874",
LostDate: "11/06/2014 16:14:19",
FoundDate: "",
LostKey: "7560733274a7ca2ec43a85fcb9abd345fdc876acffac2b75ace7946035122fbd",
Resp: "OK"
}] //<-- added ]
)

Loading remote data only once with Select2

As the title suggests I would like to load remote data once only.
I thought about loading a data with independent ajax call and set it "locally" at the control but wonder if there is more "built in" way to do so...
a solution can be found here:
https://github.com/ivaynberg/select2/issues/110
$("#selIUT").select2({
cacheDataSource: [],
placeholder: "Please enter the name",
query: function(query) {
self = this;
var key = query.term;
var cachedData = self.cacheDataSource[key];
if(cachedData) {
query.callback({results: cachedData.result});
return;
} else {
$.ajax({
url: '/ajax/suggest/',
data: { q : query.term },
dataType: 'json',
type: 'GET',
success: function(data) {
self.cacheDataSource[key] = data;
query.callback({results: data.result});
}
})
}
},
width: '250px',
formatResult: formatResult,
formatSelection: formatSelection,
dropdownCssClass: "bigdrop",
escapeMarkup: function (m) { return m; }
});
Edit:
I might have misinterpreted your question. if you wish to load all data once, then use that is Select2, there is no built in functionality to do that.
Your suggestion to do a single query, and then use that stored data in Select2 would be the way to go.
This is for Select2 v4.0.3:
I had this same question and got around it by triggering an AJAX call and using the data returned as the initialized data array.
// I used an onClick event to fire the AJAX, but this can be attached to any event.
// Ensure ajax call is done *ONCE* with the "one" method.
$('#mySelect').one('click', function(e) {
// Text to let user know data is being loaded for long requests.
$('#mySelect option:eq(0)').text('Data is being loaded...');
$.ajax({
type: 'POST',
url: '/RetrieveDropdownOptions',
data: {}, // Any data that is needed to pass to the controller
dataType: 'json',
success: function(returnedData) {
// Clear the notification text of the option.
$('#mySelect option:eq(0)').text('');
// Initialize the Select2 with the data returned from the AJAX.
$('#mySelect').select2({ data: returnedData });
// Open the Select2.
$('#mySelect').select2('open');
}
});
// Blur the select to register the text change of the option.
$(this).blur();
});
This worked well for what I had in mind. Hope this helps people searching with the same question.
To load data once:
Assumptions:
You have a REST API endpoint at /services that serves a JSON array of objects
The array contains objects which have at least a "name" and "id" attribute. Example:
[{"id": 0, "name": "Foo"}, {"id": 1, "name": "Bar"}]
You want to store that array as the global 'services_raw'
First, our function to load the data and create the global 'services_raw' (AKA 'window.services_raw'):
fetchFromAPI = function() {
console.log("fetchFromAPI called");
var jqxhr = $.ajax(
{
dataType:'json',
type: 'GET',
url: "/services",
success: function(data, textStatus, jqXHR) {
services_raw = data;
console.log("rosetta.fn.fetchServicesFromAPI SUCCESS");
rosetta.fn.refreshServicesSelect();
},
error: function(jqXHR, textStatus, errorThrown) {
console.log("Error inside rosetta.fn.fetchServicesFromAPI", errorThrown, textStatus, jqXHR);
setTimeout(rosetta.fn.fetchServicesFromAPI(), 3000); // retry in 3 seconds
}
}
)
.done(function () {
console.log("success");
console.log(jqxhr);
})
.fail(function () {
console.log("error");
})
.always(function () {
console.log("complete");
});
// Perform other work here ...
// Set another completion function for the request above
jqxhr.always(function () {
console.log("second complete");
});
};
Second, our Select2 instantiation code which transforms our data into a format that Select2 can work with:
refreshServicesSelect = function () {
// ref: http://jsfiddle.net/RVnfn/2/
// ref2: http://jsfiddle.net/RVnfn/101/ # mine
// ref3: http://jsfiddle.net/RVnfn/102/ # also mine
console.log('refreshServicesSelect called');
$("#add-service-select-service").select2({
// allowClear: true
data: function() {
var arr = []; // container for the results we're returning to Select2 for display
for (var idx in services_raw) {
var item = services_raw[idx];
arr.push({
id: item.id,
text: item.name,
_raw: item // for convenience
});
}
return {results: arr};
}
});
};
Here's what the Select2 element in HTML should look like before your call the above functions:
<input id="add-service-select-service" type="hidden" style="width:100%">
To use all of this, call (in JS):
window.fetchFromAPI();
window.refreshServicesSelect();
Lastly, here's a JSFiddle where you can play with a similar thing: http://jsfiddle.net/RVnfn/102/
Basically, in my example above, we're just using ajax to populate the equivalent of window.pills in the Fiddle.
Hope this helps :)
Please reply if you know how to do this via the Select2 .ajax function, as that would be a bit shorter.
In my condition, it is working perfectly with the given code
$('#itemid').select2({
cacheDataSource: [],
closeOnSelect: true,
minimumInputLength: 3,
placeholder: "Search Barcode / Name",
query: function(query) {
// console.log(query);
self = this;
var key = query.term;
var cachedData = self.cacheDataSource[key];
if(cachedData) {
query.callback({results: cachedData});
return;
} else {
$.ajax({
url: "./includes/getItemSelect2.php",
data: { value : query.term },
dataType: 'json',
type: 'POST',
success: function(data) {
self.cacheDataSource[key] = data;
query.callback({results: data});
}
});
}
},
});
And my data return from the ajax is in this form
<?php
$arr = [
["id" => 1, "text" => "Testing"],
["id" => 2, "text" => "test2"],
["id" => 3, "text" => "test3"],
["id" => 4, "text" => "test4"],
["id" => 5, "text" => "test5"]
];
echo json_encode($arr);
exit();
?>

"filter" json through ajax (jquery)

I'm trying to filter the json array through ajax and not sure how to do so.
{
posts: [{
"image": "images/bbtv.jpg",
"group": "a"
}, {
"image": "images/grow.jpg",
"group": "b"
}, {
"image": "images/tabs.jpg",
"group": "a"
}, {
"image": "images/bia.jpg",
"group": "b"
}]
}
i want it so that i can only show items in group A or group B.
how would i have to change my ajax to filter through the content?
$.ajax({
type: "GET",
url: "category/all.js",
dataType: "json",
cache: false,
contentType: "application/json",
success: function(data) {
$('#folio').html("<ul/>");
$.each(data.posts, function(i,post){
$('#folio ul').append('<li><div class="boxgrid captionfull"><img src="' + post.image + '" /></div></li>');
});
initBinding();
},
error: function(xhr, status, error) {
alert(xhr.status);
}
});
Also, how can I can I make each link process the filter?
Group A Group B
Sorry for all these questions, can't seem to find a solution..
Any help in the right direction would be appreciated.
Thanks!
You'll need to write a filter function, more than likely:
function filterGroup(obj, filteredGroup) {
var resultObj = $.extend({},obj);
for (var i in obj) {
if ( obj.hasOwnProperty(i) ) {
if ( obj[i].group && obj[i].group !== filteredGroup ) {
delete resultObj[i];
}
}
}
return resultObj;
}
Then you'd just run your data through that filter. You'll also probably want to switch to a POST with a bunch of JSON like this.
$.ajax({
type: "POST",
url: "category/all.js",
dataType: "json",
cache: false,
data: {"posts": filterGroup(posts, 'a')},
contentType: "application/json",
success: function(data) {
$('#folio').html("<ul/>");
$.each(data.posts, function(i,post){
$('#folio ul').append('<li><div class="boxgrid captionfull"><img src="' +
post.image + '" /></div></li>');
});
}
});
Most of this code is hypothetical since I don't know exactly what you're doing, but it should get you close. Just don't expect to be able to copy/paste it. This assumes you actually named your data variable as posts for instance.
To make a link run code, you'll need to attach a click handler and identify each link. I'll assume you added a classname to each (filterA and filterB):
$('.filterA').click(function(){
filterGroup(someDataObject, 'a');
return false;
});
$('.filterB').click(function(){
filterGroup(someDataObject, 'b');
return false;
});

Categories