I have jsTree working with JSON data: the JSON data represents the server's file system, and the user can select a folder from the tree, which is then added to the folder input field). I don't want the page to load without the top three levels of the file system provided. However, I don't parse the whole file system because that would take too long.
Can I pre-populate jsTree with JSON data and use Ajax when the user opens nodes further down the tree which were not pre-populated, or do I have to use Ajax for the initial load as well?
Below I show my current code (without any Ajax), but only retrieving data down to one level for the sake of brevity: it returns C:\ and E:\ file systems from the server. This works, but I'm unclear how to introduce Ajax to this when the user tries to open a node further down the hierarchy.
<label for="folder">Selected Folder</label>
<input type="text" name="folder" id="folder">
<br>
<script type="text/javascript">
function createJSTree(jsondata)
{
$('#jstree').jstree(
{
"plugins" : ["themes","html_data","ui","cookie"],
'core':
{
'data': jsondata
}
}
)
.bind("select_node.jstree",
function (e, data)
{
var objNode = data.instance.get_node(data.selected);
document.getElementById('folder').value=objNode.id;
}
)
;
}
$(function() { var jsondata ={"text":"pclaptop","children":[{"id":"C:\\","text":"C:\\","children":[]},{"id":"E:\\","text":"E:\\","children":[]}]}; createJSTree(jsondata); })
</script>
Before I get into the ajax piece of the code I had to set the check_callback parameter in jsTree it enables editing of the jsTree. Next, I call `$('#jstree').jstree().create_node('#', parsedData, "last"); in the success method of jQuery's ajax call, and that did the trick. My solution is below:
index.html
<label for="folder">Selected Folder</label>
<input type="text" name="folder" id="folder">
<br>
<button id="create-node-button">
Create Node
</button>
<div id="jstree"></div>
<script type="text/javascript">
function createJSTree(jsondata) {
$('#jstree').jstree({
"plugins": ["themes", "html_data", "ui", "cookie"],
'core': {
'check_callback': true,
'data': jsondata
}
})
.bind("select_node.jstree",
function(e, data) {
var objNode = data.instance.get_node(data.selected);
document.getElementById('folder').value = objNode.id;
}
);
}
$(function() {
var jsondata = [{
"id": "pclaptop",
"parent": "#",
"text": "pclaptop"
},
{
"id": "C:\\",
"parent": "pclaptop",
"text": "C:\\"
},
{
"id": "E:\\",
"parent": "pclaptop",
"text": "E:\\"
},
{
"id": "F:\\",
"parent": "pclaptop",
"text": "F:\\"
}
];
createJSTree(jsondata);
$("#create-node-button").on("click", function() {
$.ajax({
url: "./data.json",
success: function(data){
var parsedData = JSON.parse(data);
$('#jstree').jstree().create_node('#', parsedData, "last");
}
});
});
});
</script>
data.json
{ "id" : "ajson5", "text" : "newly added" }
Lastly, here is a fiddle . I wasn't sure of how to properly set up the ajax call in jsfiddle so I did it locally instead.
Related
I've successfully created a webscript to that returns a JSON response. See below:
get.js file:
// search for folder within Alfresco content repository
var folder = roothome.childByNamePath("PATH");
// validate that folder has been found
if (folder == undefined || !folder.isContainer) {
status.code = 404;
status.message = "Folder " + " not found.";
status.redirect = true;
}
// construct model for response template to render
model.folder = folder;
get.json.ftl:
{"corporates" : [
<#recurse_macro node=folder depth=0/>
]
}
<#macro recurse_macro node depth>
<#list node.children?sort_by(["properties","name"]) as child>
{
"Name" : "${child.properties.name}",
"URL" : "${child.url}",
"serviceURL" : "${child.serviceUrl}",
"shareURL" : "${child.shareUrl}",
"ID" : "${child.id}",
"Type" : "${child.typeShort}"
},
<#if child.isContainer>
{
<#recurse_macro node=child depth=depth+1/>
}
</#if>
</#list>
</#macro>
This returns JSON cleanly (woohoo!), but I would like to grab the JSON from a second webscript using AJAX.
Currently, I am utilizing a typical AJAX call in my second webscript's get.html.ftl file like this:
$(document).ready(function() {
$('.submit-button').click(function(e) {
// Avoid to trigger the default action of the event.
e.preventDefault();
// Actions declared here...
$.ajax({
type: 'GET',
dataType: 'html',
url: 'PLACEHOLDER_URL_PATH',
success: function(data) {
// Shows the result into the result panel.
$('#alfresco-result').html(data);
alert('Done.');
},
error: function(data) {
// Shows the result into the result panel.
$('#alfresco-result').html("ERROR");
}
});
});
})
My question is why the AJAX call doesn't work when I use dataType: 'json'?
I would like to parse through the JSON in my AJAX call and turn it into html (e.g. an html list), but it's not accepting the JSON dataType as an acceptable input.
Any help is appreciated!
You can use POST Webscript Call using ajax like this and pass your jsonObject
dataObj:"yourJsonObject",
to dataObject
Alfresco.util.Ajax.jsonPost(
{
url: Alfresco.constants.PROXY_URI + "sample/mypostwebscript",
dataObj:"yourJsonObject",
successCallback: {
fn: function(res){
alert("success");
alert(res.responseText);
},
scope: this
},
failureCallback:
{
fn: function(response)
{
// Display error message and reload
Alfresco.util.PopupManager.displayPrompt(
{
title: Alfresco.util.message("message.failure", this.name),
text: "search failed"
});
},
scope: this
}
});
},
I'm using the JQuery UI autocomplete plugin (cached version) with JQuery-UI 1.11.1
Due to some server-side changes in the JSON I am using as source, I need to adapt my code.
Here is an example of my JSON:
[{
"name": "Varedo"
}, {
"name": "Varena"
}, {
"name": "Varenna"
}, {
"name": "Varese"
}]
produced by an URL with this style:
[url]/?name=vare
Since the GET variable is different from the default one ("term"), I already adapted my code for the custom request as suggested here:
$(function () {
var cache = {};
$("#searchTextField").autocomplete({
minLength: 3,
source: function (request, response) {
var term = request.term;
if (term in cache) {
response(cache[term]);
return;
}
$.getJSON("[url]", {
name: request.term
}, function (data, status, xhr) {
cache[term] = data;
response(data);
});
}
});
});
However I need to also adapt the code in order to use a custom JSON value (the default is "value" http://api.jqueryui.com/autocomplete/#option-source) which is in my case is "name" (as you can see from the JSON).
How can I do that?
At the moment this is what I get from the autocomplete:
So I guess I am somehow giving as response JS Objects and not strings.
Thanks in advance.
Currently you're saving the response as it is into your cache object, which is not valid format for jQuery UI autocomplete. You should convert the data into proper format digestable for autocomplete.
Either you should pass an array of strings, or an array of objects having label and value properties.
Since the response only contains name properties, you can convert it into an array of strings using jQuery map() method and save it in cache variable as follows:
$("#searchTextField").autocomplete({
minLength: 3,
source: function (request, response) {
var term = request.term;
if (term in cache) {
response(cache[term]);
return;
}
$.getJSON("[url]", {
name: request.term
}, function (data, status, xhr) {
cache[term] = $.map(data, function (obj) { // returns array of strings
return obj.name
});
// return the new array rather than original response
response(cache[term]);
});
}
});
Using the included http post, I should get back the JSON object below. I want to take the LeagueDictionary data in the JSON below and create an object so I can use it in a for each loop on my client, but I can't wrap my head around how to structure that code in the http call.
{
"Id": 0,
"UserName": null,
"NickName": null,
"Email": "email#company.com",
"Password": null,
"Admin": false,
"Validated": false,
"Key": "oOE0QbOhjK17pNeKDPEFti5On27R3b",
"LeagueDictionary": {
"1": "League #1",
"2": "League #2"
}
}
using this call:
$scope.getLeagues = function() {
$http({
method: 'POST',
url: 'http://xxxxxxxxxxxxxxxxxx',
data: ???,
})
}
If someone give me a nudge on how to data bind that particular part of the JSON, I'd appreciate the help. I'm not sure how to strip the LeagueDictionary section out and make an object out of it.
You could set up a service that gets your data, so you can get $http and such out of your controller. Say...
app.factory('DataService', function ($http) {
return {
get: function () {
return $http.get('data.json'); // post & url goes here
}
};
});
In your controller, use then to access the response data after promise has been resolved (catch() and finally() are available, too).
app.controller('MainCtrl', function ($scope, DataService) {
DataService.get().then(function (response) {
$scope.leagueDictionary = response.data.LeagueDictionary;
});
});
Related HTML template would be
<body ng-controller="MainCtrl">
<div ng-show="leagueDictionary">
<span ng-repeat="(key,val) in leagueDictionary">
{{ val }} <br>
</span>
</div>
</body>
Using your data this gives you
See example plunker here http://plnkr.co/edit/j6bmmQ
You can just access the LeagueDictionary property of the response, and then iterate over that in ng-repeat. Obviously I don't know exactly what your scopes look like, but this should get you started:
//JS
$http.post('/someUrl', { 'foo': 'bar' }).success(function(data) {
myController.myModel.leagueDictionary = data.LeagueDictionary;
});
//HTML
<tr ng-repeat="(leagueNum, leagueName) in leagueDictionary">
The icanhaz documentation uses this as an example as how to pull ich templates from a remote server.
$.getJSON('/myserver/templates.json', function (templates) {
$.each(templates, function (template) {
ich.addTemplate(template.name, template.template);
});
});
However, the documentation doesn't really tell you what the file on the remote server has to look like. Anyone have any ideas?
Your templates JSON object may look like this:
{
"templates": {"name": "optionTemplate",
"template": "{{#options}}<option value='{{value}}'>{{display}}</option>{{/options}}"
}
}
This will define a template for options in a select box.
You can add the template using the code you specified (actually I tweaked it slightly as I couldn't get it to work as specified):
$.getJSON('templates.json', function (templates) {
$.each(templates, function () {
ich.addTemplate(this.name, this.template);
});
});
//now call getJSON on your input data
$.getJSON('options.json', function (data) {
var optionElements = ich.optionTemplate(data);
$('#selectBox').append(optionElements);
}
For clarity, here is what options.json contains:
{
"options": [
{ "value": "optionValue",
"display": "optionDisplay"
},
{ "value": "optionValue2",
"display": "optionDisplay2"
}]
}
Do let me know how you get on :)
I've just decided to learn knockoutjs, and I'm having a bit of an issue binding some json to my viewmodel. I've searched heaps on it, tried heaps of things, but I must have missed something.
Javascript:
var data = {
"TestList": [{ "ID": "1", "Name": "Dave" }, { "ID": "2", "Name": "Mustaine" }],
"TestText": "Hello World"
};
var viewModel = {};
ko.mapping.fromJSON(data, viewModel);
ko.applyBindings(viewModel);
HTML
TestText: <span data-bind="text: TestText"></span><br>
TestList: <select id="TestList"
data-bind="
options: TestList,
optionsText: 'Name',
optionsValue: 'ID',
optionsCaption: 'Please Select'"></select>
EDIT
the variable 'data' was used as an example of the json I get back from the server. Anyways, I've updated the above code with getJSON and getting an error which the above example really can't give me as it doesn't use getJSON.
Updated JAVASCRIPT:
var viewModel;
$.getJSON('/myurl',
function (data) {
viewModel = data;
});
alert(viewModel);
$(function() {
ko.applyBindings(viewModel);
});
The issue i'm having here is that it works.. as long as the alert box is there. If i comment that line out, it doesn't work!
Your first issue is that you are declaring data as an array with only one member in it, but you are not referring to this array within your data-bind declarations.
Secondly if you have data as a JavaScript object you do not need fromJSON on it.
Updated JS Code:
var data = {
"TestList": [{ "ID": "1", "Name": "Dave" }, { "ID": "2", "Name": "Mustaine" }],
"TestText": "Hello World"
};
var viewModel = data;//{};
ko.applyBindings(viewModel);
Working fiddle: http://jsfiddle.net/AfgAG/19/
EDIT: Updated answer to reflect the updates in the question and also the initial answer.\
Your view model needs to have the options list as an observable array for the options binding to work.
Also, it is better to start off your view model with structure defined and the observables defined for the data binding to work when you update with your AJAX call.
See below for updated javascript code. Could not create a fiddle as I was unable to access the fiddle side.
var viewModel =
{
TestText: ko.observable('My Initial Text'),
TestList: ko.observableArray([])
}
ko.applyBindings(viewModel);
// using set time out here to simulate your ajax call.
setTimeout(function () {
// this would normally be the content for your getJson success method.
// this is where you use your from JSON.
// data is a javascript object from ajax response.
var data = {
"TestList": [{ "ID": "1", "Name": "Dave" }, { "ID": "2", "Name": "Mustaine" }],
"TestText": "Hello World"
};
// update the view model observable properties.
viewModel.TestText(data.TestText);
viewModel.TestList(data.TestList);
}, 2000);
I've figured it out. FYI, This is what i did:
javascript
var viewModel = (function () {
var self = this;
this.model = ko.observableArray([]);
$.getJSON('/myurl',
function (data) {
self.model = ko.mapping.fromJS(data, self.model);
ko.applyBindings(self.model);
});
});
ko.applyBindings(new viewModel());
html
<span data-bind="text: TestText"></span>
<select id="TestList"
data-bind="
options: TestList,
optionsText: 'Name',
optionsValue: 'ID',
optionsCaption: 'Please Select'"></select>