JsTree with JSON stuck on loading - json

I am using JSON to display a JsTree. The JSON is being built up as a string via a recursive function. Now I went through a few tests with smaller/less complicated trees and got it to work. I used JSONLint to check for valid JSON and eventually got the correct syntax. Now when I try and display the intended big tree its just stuck with the loading .gif (which used to be because the JSON was incorrect) but after checking it on JSONLint it was correct.
Any possible causes for this? I doubt the tree could be too big or anything.
Recursive Function:
public void getViewTree(ref string tree, Int32? id = null)
{
var topNodes = (from items in db.AssessmentViewItems
select items).Take(1);
#region getChildren via LINQ
if (id == null)
{
topNodes = from items in db.AssessmentViewItems
where items.ParentAssessmentViewItemID == null
&& items.AssessmentViewID == 17
select items;
}
else
{
topNodes = from items in db.AssessmentViewItems
where items.ParentAssessmentViewItemID == id
&& items.AssessmentViewID == 17
select items;
}
#endregion
int counter = 1;
int max = (int)topNodes.Count();
foreach (var node in topNodes)
{
if (node.ParentAssessmentViewItemID == null)
{
{\"id\":\"532topNode\",\"selected\":true},\"children\":[null,
tree += "{\"data\":\"" + node.Title.Trim().Replace("\"","").Replace("("," ").Replace(":"," ").Replace("-"," ").Replace("&","and").Replace("/"," ").Replace("\\"," ").Replace(","," ").Replace("•", " ") + "\",\"attr\":{\"id\":\"" + node.AssessmentViewItemID + "\", \"selected\":true}, \"children\":[";
getViewTree(ref tree, node.AssessmentViewItemID);
tree += "}]";
if (counter < max)
{
tree += "},";
}
}
else if (node.Type.Equals("Legal Topic"))
{
tree += "{\"data\":\"" + node.Title.Trim().Replace("\"", "").Replace("(", " ").Replace(":", " ").Replace("-", " ").Replace("&", "and").Replace("/", " ").Replace("\\", " ").Replace(",", " ").Replace("•", " ") + "\",\"attr\":{\"id\":\"" + node.AssessmentViewItemID + "\", \"selected\":true}";
if (counter < max)
{
tree += "},";
}
}
else
{
var topNodes1 = from items in db.AssessmentViewItems
where items.ParentAssessmentViewItemID == node.AssessmentViewItemID
&& items.AssessmentViewID == 17
select items;
if (topNodes1.Count() > 0)
{
tree += "{\"data\":\"" + node.Title.Trim().Replace("\"", "").Replace("(", " ").Replace(":", " ").Replace("-", " ").Replace("&", "and").Replace("/", " ").Replace("\\", " ").Replace(",", " ").Replace("•", " ") + "\",\"attr\":{\"id\":\"" + node.AssessmentViewItemID + "\", \"selected\":true}, \"children\":[";
}
else
{
tree += "{\"data\":\"" + node.Title.Trim().Replace("\"", "").Replace("(", " ").Replace(":", " ").Replace("-", " ").Replace("&", "and").Replace("/", " ").Replace("\\", " ").Replace(",", " ").Replace("•", " ") + "\",\"attr\":{\"id\":\"" + node.AssessmentViewItemID + "\", \"selected\":true}";
}
getViewTree(ref tree, node.AssessmentViewItemID);
if (topNodes1.Count() > 0)
{
tree += "}]";
}
if (counter < max)
{
tree += "}";
tree += ",";
}
}
counter++;
}
}
JS:
$(function () {
$("#demoTree").jstree({
"json_data": {
"data": treeModel
},
"plugins": ["themes", "json_data", "ui"],
});
});
Calling Recursive Function:
string tree = "[";
getViewTree(ref tree);
tree += "}]";
return View("About", "_Layout", tree);
After using Chrome Dev Tools, the error that I get from it:
Uncaught SyntaxError: Unexpected token ILLEGAL (program):54
Uncaught Neither data nor ajax settings supplied.
I did check it for syntax on JSONLint. Small tree is generated fine without those 2 errors

Problem got solved by using DevExpress tree. Exact same JSON string.

Related

Using recursion, how do you iterate over an object to produce HTML?

I am trying to sort an object of key:values recursively. It seems to work , at least to the console. The code takes the object and iterates over the key value pairs. If it finds another object it calls itself to iterate over that object. The problem I have is that the subsequent call doesn't seem to produce any html, but it does show the key value pairs in the console. This is my first attempt at recursion, I'm not sure if it's the way I'm declaring variables or if I'm missing something in how recursion works.
$(document).ready(function(){
let conditionReport = {
weekNo:"5",
laps:"8",
heat:"6",
feature:"9",
tireSize:
{lf:"15",lr:"16",rf:"16.5",rr:"17"},
airPressure:
{lf:"8",lr:"10",rf:"12",rr:"16"},
tireTemperature:
{lf:"9",lr:"11",rf:"13",rr:"15"},
suspensionAdjustment:
{lf:"4",lr:"5",rf:"6",rr:"7"},
engineRPM:"2000",
trackCondition:"4",
damage2car:"3",
suspensionAdjustment2:
{upper:
{lf:"4",lr:"5",rf:"6",rr:"7"},
lower:
{lf:"4",lr:"5",rf:"6",rr:"7"},
},
notes:"note 3"
}
s = x => document.getElementById(x);
const isObject = val => (typeof val === "object") ? true : false;
const getKeyValue = (obj) => {
let html = '<ul>';
for(let key in obj) {
let value = obj[key]
if(!isObject(value)){
//console.log(isObject(value));
console.log(key + ":" + value);
html += '<li>' + key + ":" + value + "</li>";
}
else{
if(isObject(value)){
//console.log(isObject(value));
console.log(key + "=>");
getKeyValue(value);
html += '<li>' + key + ":"+ "</li>";
}
}
}
html += "</ul>";
s('cards').innerHTML = html;
}
getKeyValue(conditionReport);
});
Use return values:
const getKeyValue = (obj) => {
let html = '<ul>';
for (let key in obj) {
let value = obj[key]
if (!isObject(value)) {
html += '<li>' + key + ":" + value + "</li>";
} else {
var innerValue = getKeyValue(value);
// ^^^^^^^^^^^^^^^^
html += '<li>' + key + ":"+ innerValue + "</li>";
// ^^^^^^^^^^
}
}
html += "</ul>";
return html;
// ^^^^^^
}
Then do
s('cards').innerHTML = getKeyValue(conditionReport);

What is the right way to compare as3 objects using hamcrest

I'm trying to compare two objects to see if they are the same using hamcrest for flex-unit, but when the object has sub objects, it just throws an error:
Error: Expected: (An array containing <[object Object]>
but: an array containing <[object Object]> was <[object Object]>
I want it to do an assertThat(..., hasProperties(...)); on the sub object.
Is there a way to get that or should i create a custom matcher?
EDIT
An example of the object structure i want to test:
var expected:Object = {
number:1.3,
array:[{
prop1:"val1", prop2:"val2"
}]
anObject:{
propA:1, propB:2
},
}
var objectUnderTest:Object = {
number:1.3,
array:[{
prop1:"val1", prop2:"val2"
}]
anObject:{
propA:1, propB:2
},
}
assertThat("should be the same", objectUnderTest, hasProperties(expected));
since the expected and objectUnderTest have the same structure, the test should pass, but is returning the error:
Error: Expected: (An array containing <[object Object]>
but: an array containing <[object Object]> was <[object Object]>
Also, if there is a way to compare two JSON strings will be fine too.
EDIT2
This is my final version after djib help:
package com
{
public function assertEqualsObjects(message:String, object1:Object, object2:Object):Boolean
{
// we have to run it both ways (1-2, 2-1)
return (compare(object1, object2, message + ": object") && compare(object2, object1, message + ": extra"));
}
}
import org.flexunit.asserts.fail;
function compare(object1:Object, object2:Object, parent:String):Boolean
{
var count:int = 0;
for (var s:String in object1)
{
count ++;
if (!object2.hasOwnProperty(s))
{
fail(parent + "." + s + " expected: " + object1[s] + " but was: undefined");
return false;
}
if (!compare(object1[s], object2[s], parent + "." + s))
{
fail(parent + "." + s + " expected: " + object1[s] + " but was: " + object2[s]);
return false;
}
}
if (count == 0 && object1 != object2) // if object has no properties, compare their actual values
{
fail(parent + " expected: " + object1 + " but was: " + object2);
return false;
}
return true;
}
I've put this code together. Recursion is the key ^^
// our two objects to compare ...
var obj1 = {
number:1.3,
array:[{prop1:"val1", prop2:"val2"}],
anObject:{propA:1, propB:2}
};
var obj2 = {
number:1.3,
array:[{prop1:"val1", prop2:"val2"}],
anObject:{propA:1, propB:2}
};
trace(isSame(obj1, obj2)); // -> true
function isSame(object1:Object, object2:Object):Boolean
{
// we have to run it both ways (1-2, 2-1)
return (compare(object1, object2) && compare(object2, object1));
}
function compare(object1:Object, object2:Object):Boolean
{
var count:int = 0;
for (var s:String in object1)
{
count ++;
if (object2[s] == undefined)
return false;
if (!compare(object1[s], object2[s]))
return false;
}
if (count == 0 && object1 != object2) // if object has no properties, compare their actual values
return false;
return true;
}

ActionScript String Concatenation in for loop

So I am struggling with loops.
I have a mobile app with dynamic controls that I add from a sqlite database, it is a list of questions and based on the question type, I add the relevant type of control to the page along with the question, this all works fine.
I then loop through all the controls looking for answers, so I can loop through 60 quesitons and return the values from the relevant textboxes, checkboxes and toggle switches.
The for loop runs like this
if (displayObject is DisplayObjectContainer && currentDepth < maxDepth)
{
for (var i:int = 0; i < DisplayObjectContainer(displayObject).numChildren; i++)
{
traceDisplayList(DisplayObjectContainer(displayObject).getChildAt(i), maxDepth, skipClass, levelSpace + " ", currentDepth + 1);
if (displayObject is TextInput ||displayObject is CheckBox || displayObject is Label || displayObject is ToggleSwitch )
{
if(displayObject["id"] =="QuestionText"&& (i==0))
{
if(displayObject["text"] != null)
{
questionString= (displayObject["text"]);
trace ("Question: " + questionString);
}
}
else if (displayObject["id"] == "QuestionResponse")
{
if(displayObject["text"] != null)
{
answerString = (displayObject["text"]);
trace ("Answer: " + answerString);
}
}
else if (displayObject["id"]== "CheckboxResult")
{
if(displayObject["selected"] != null)
{
checkboxAnswer = (displayObject["selected"]);
trace ("Check / Toggle: " + checkboxAnswer);
}
}
}
}
}
My question is, the results I get back look like this;
questionstring value
answerstring value
checkbox value
what I want is
questionstring value, answerstring value, checkbox value
I cannot for the life of me see how I get these values into 1 row.
Any tips appreciated
Trace just prints info to the console mainly for debugging if you really want all of that on one line in the console you just need to create a string and then add "Question: " + questionString + " Answer: " + answerString + " Check / Toggle: " + checkboxAnswer to the string after you have found them all and then call trace with your string you made. something like this
var mystring:String
mystring="";
if(displayObject["id"] =="QuestionText"&& (i==0))
{
if(displayObject["text"] != null)
{
questionString= (displayObject["text"]);
mystring += "Question: " + questionString;
}
}
else if (displayObject["id"] == "QuestionResponse")
{
if(displayObject["text"] != null)
{
answerString = (displayObject["text"]);
mystring += "Answer: " + answerString;
}
}
else if (displayObject["id"]== "CheckboxResult")
{
if(displayObject["selected"] != null)
{
checkboxAnswer = (displayObject["selected"]);
mystring += "Check / Toggle: " + checkboxAnswer;
}
}
trace(mystring);

AS: if statement evaluating incorrectly

I have a very simple piece of logic as follows:
var divert:Number = 0;
for (var connection in _connections) {
trace("target: " + _connections[connection].target + " || i: " + (i + 1));
if(int(_connections[connection].target) != (i + 1)) {
trace("bad connection");
divert++;
}
}
The problem is that when i + 1 and int(_connections[connection].target) are equal the if statement is returning true as can be seen in the output of my trace() statements below:
target: 0 || i: 1
bad connection
target: 1 || i: 1
bad connection
Can anyone see what could be causing this to happen?
EDIT: The function this is contained in as per request:
public function loadListener(i:Number, onProgress:Function, onComplete:Function):Void
{
trace("load listening to: "+i);
trace("next in queue: " + _queues["lower"][0] + " | " + _queues["upper"][0]);
_functions[i] = {onProgress:onProgress, onComplete:onComplete};
if (_queues["lower"][0] != i + 1 || _queues["upper"][0] != i + 1) {
var divert:Number = 0;
for (var connection in _connections) {
trace("target: "+_connections[connection].target+" || i: "+(i+1));
if(int(_connections[connection].target) != (i + 1)) {
trace("bad connection");
divert++;
}
}
if (divert == _connections.length) {
_diversion = i + 1;
trace("divert: "+divert+" || connections: "+_connections.length);
}
}
}
First of all, why use a for(var) loop when you can use
var divert:Number = 0;
for each(var connection in _connections) {
trace("target: " + connection.target + " || i: " + (i + 1));
if(int(connection.target) != (i + 1)) {
trace("bad connection");
divert++;
}
}
To debug further, replace
trace("target: " + connection.target + " || i: " + (i + 1));
with
trace("target: " + int(connection.target) + " || i: " + (i + 1));
If this traces zero, you know where the issue is.
You could try doing
if(connection.target.toString() != (i + 1).toString()) {

How to elegantly plot charts in ASP.NET MVC 3 using Highcharts?

I've been working with highcharts and MVC 3 for two years by now (I never done anything complicated, just load data and make it work stuff), and I worked with two different scenarios:
Chart code written in the directly in the view, loading data through Json
Html helper responsible to plot the chart
The Html helper approach seems to me a more elegant choice ... but then, just to illustrate to you guys, here is how it looks like (just part of it):
public static string DisplayChart(
this HtmlHelper helper,
ChartOptions options,
TimedChartSeries[] data)
{
string[] axisList = data.GroupBy(t => t.Unit).Select(t => t.Key).ToArray();
string result = "";
result += "<script type=\"text/javascript\">\n";
result += "var " + options.ChartName + ";\n";
result += "$(document).ready(function() {\n";
result += options.ChartName + "= new Highcharts.Chart({\n";
result += "chart: {renderTo: '" + options.DivName + "',zoomType: ''},\n";
result += "title: { text: '" + options.Title + "'},\n";
result += "subtitle: {text: '" + options.SubTitle + "'},\n";
result += "xAxis: { type: 'datetime'," +
"\n dateTimeLabelFormats: {month: '%e. %b', year: '%b' },"
+ "labels:{rotation: -45}\n},\n";
string axes = "";
for (int i = 0; i < axisList.Length; i++)
{
var temporaryData = data.First(t => t.Unit == axisList[i]);
if (i != 0)
axes += ", ";
axes += "{labels:{\n " +
"formatter : function(){return this.value + '" + temporaryData.Unit + "';},\n" +
"style:{color:'#" + temporaryData.Color.Name.Remove(0, 2) + "'}},\n" +
"title:{text:'',style:{color:'#" + temporaryData.Color.Name.Remove(0, 2) + "'}},\n" +
"}\n";
}
result += "yAxis: [\n" + axes + "],\n";
string units = "";
for (int i = 0; i < data.Length; i++)
{
if (i != 0)
units += ", ";
units += "'" + data[i].Title + "': '" + data[i].Unit + "'\n";
}
result += "tooltip:{\nshared: true,\n backgroundColor: 'none' ,\nborderColor: 'none'," +
"\nshadow:false\n ,crosshairs: true,\n" +
"formatter: function() {var s = '<table class=\"table-list\"><tr><th>Hora</th><th>'+ test(this.x) +'</th></tr>';" +
"\n$.each(this.points, function(i, point) {" +
"\ns += '<tr><td>'+point.series.name + '</td><td>'+point.y+'</td></tr>'});s+='</table>';" +
"\n$('#tooltip').html(s);}},";
result += "lang: {" +
"months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho'," +
"'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro']," +
"weekdays: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado']},";
string series = "";
int x = 0;
for (int j = 0; j < axisList.Length; j++)
{
var temporaryData = data.Where(t => t.Unit == axisList[j]).ToArray();
for (int i = 0; i < temporaryData.Length; i++)
{
if (x > 0)
series += ", ";
series += "{name: '" + temporaryData[i].Title + "',\n color: '#" + temporaryData[i].Color.Name.Remove(0, 2) +
"', \ntype: '" + temporaryData[i].Type + "',\nunit:'" + temporaryData.First().Unit + "', \nyAxis:" + j + " , \ndata:[" + FromArrayToString(temporaryData[i].Data) +
"], marker: { enabled: false}}\n";
x++;
}
}
result += "series: [\n" + series + "]\n";
result += "});});";
result += "\nfunction test(i)\n{\nvar j = new Date(i + 2*60*60*1000);\n" +
"return new Date(i + 3*60*60*1000).format('d/m/Y H:i:s.')+j.getMilliseconds();\n}\n</script>";
result += "\n<div id=\"" + options.DivName + "\" style=\"width:" + options.Width + ";height: " + options.Height + "\"></div>" +
"<div id=\"tooltip\"></div>";
return result;
}
It's really simple to call this helper:
#Html.Raw(Html.DisplayChart((ChartOptions)Model.Options,(TimedChartSeries[])Model.Series))
As you guys can see, I have to use the Html.Raw helper in order to make it work ... that is problem nº 1 (and it probably has an easy solution). But the second problem is really great: the chart becomes entirely tied to my domain. If I wanted to plot a, say, bar chart displaying data of the last 3 years in months (each month being represented by a bar), it would be impossible to use this helper.
And it also looks kind of ugly.
So, guys, which option do you think is more elegant, the Json or the Helper approach?
About the use of Html.Raw and the easy solution:
Change your function to
public static HtmlString DisplayChart(this HtmlHelper helper, ...)
{
...
return new HtmlString(result);
}
You then may use #Html.DisplayChart(...) in your razor views.
Also, please make sure that options.DivName, options.Title, options.SubTitle etc. are properly escaped - a title like Everybody's favorite chart will break the output.