My Telerik MVC Dropdowntree reports the error "Object doesn't support property or method 'level'" for the datasource.
Can someone take a look below and tell me what's wrong?
The MVC looks like this
#(Html.Kendo().DropDownTree()
.Name("dropdowntree")
.DataTextField("Name")
.DataValueField("Id")
.HtmlAttributes(new { style = "width: 100%" })
.DataSource(dataSource => dataSource
.Read(read => read
.Action("DoLayers2", "Dev")
)
)
)
My controller returns the following JSON:
[
{
"Id":1,
"ParentCategoryId":0,
"Name":"First Layer",
"items":[
{
"Id":2,
"ParentCategoryId":1,
"Name":"First SubLayer1",
"items":[
]
},
{
"Id":3,
"ParentCategoryId":1,
"Name":"First SubLayer2",
"items":[
]
},
{
"Id":4,
"ParentCategoryId":1,
"Name":"First SubLayer3",
"items":[
]
}
]
},
{
"Id":5,
"ParentCategoryId":0,
"Name":"Second Layer",
"items":[
{
"Id":6,
"ParentCategoryId":5,
"Name":"Second SubLayer1",
"items":[
]
},
{
"Id":7,
"ParentCategoryId":5,
"Name":"Second SubLayer2",
"items":[
{
"Id":8,
"ParentCategoryId":7,
"Name":"Sub -3",
"items":[
]
}
]
}
]
}
]
Apparently my post has too much code and not enough details so I have to write something foolish at the end of the post to trick the system into allowing me to post it. This is rather annoying.
I'm not sure you can return the whole tree and bind it to the dropdowntree...
If you check telerik's demo you see that they only returns one level at a time, so In your case I think it only wants first level Id:1 and Id:5 at first and then it will automatically ask for second level for each branch...
(Id:1 will return 2, 3, 4 and Id:5 will return 6, 7 and Id:7 will return 8)
You will also have to return if there are any children for each node:
[
{ "Id":1, "Name":"First Layer", "hasChildren": true },
{ "Id":5, "Name":"Second Layer", "hasChildren": true }
]
Hope it helps!
Related
We are using https://www.npmjs.com/package/botbuilder to build a bot for Microsoft Teams.
We have the following payload to create a card, which has an Input.ChoiceSet inside an Action.ShowCard card.
It works fine when I preview the card from the bar but it doesn't work after I send the card. Sometimes if I restart the MST client it works when I click on a card for the first time but then it doesn't work after that. Sometimes it never works, only from the preview.
It does work fine on Android but it doesn't work on Linux, Mac or web clients.
Here is a demo of the issue, https://www.loom.com/share/7cfec55b587941899cd66e1d896df065
And here is the payload. Try the Click me! button, which should display a dropdown.
{
"type":"message",
"attachments":[
{
"contentType":"application/vnd.microsoft.card.adaptive",
"content":{
"$schema":"http://adaptivecards.io/schemas/adaptive-card.json",
"type":"AdaptiveCard",
"version":"1.2",
"actions":[
{
"type":"Action.OpenUrl",
"title":"Action 1",
"url":"https://my.website.com"
},
{
"type":"Action.Submit",
"title":"Action 2",
"data":{
"command":"action 1",
"data":"asdasd"
}
},
{
"type":"Action.ShowCard",
"title":"Click me!",
"card":{
"type":"AdaptiveCard",
"version":"1.0",
"body":[
{
"type":"Input.ChoiceSet",
"id":"SelectUser",
"style":"compact",
"value":"1",
"choices":[
{
"title":"User 1",
"value":"1"
},
{
"title":"User 2",
"value":"2"
},
{
"title":"User 3",
"value":"3"
}
],
"height":"stretch",
"wrap":true,
"isMultiSelect":false
}
],
"actions":[
{
"type":"Action.Submit",
"title":"Action 3.1",
"data":{
"command":"action 3.1",
"data":"asdasd"
}
}
]
}
},
{
"type":"Action.ShowCard",
"title":"Action 4",
"card":{
"type":"AdaptiveCard",
"body":[
{
"type":"Input.Text",
"label":"Enter comment",
"style":"text",
"id":"text",
"isMultiline":true,
"placeholder":"Enter your comment"
}
],
"actions":[
{
"type":"Action.Submit",
"title":"Save",
"data":{
"command":"save",
"data":"asdasd"
}
}
]
}
}
],
"body":[
{
"type":"TextBlock",
"size":"medium",
"weight":"bolder",
"text":"text... text... text",
"wrap":true
},
{
"type":"ColumnSet",
"columns":[
{
"type":"Column",
"width":"auto",
"items":[
{
"type":"Image",
"style":"Person",
"url":"https://avatar.com/avatar.png",
"size":"small"
}
]
},
{
"type":"Column",
"width":"stretch",
"items":[
{
"type":"TextBlock",
"weight":"lighter",
"text":"text... text... text",
"wrap":true
},
{
"type":"TextBlock",
"spacing":"None",
"text":"text... text... text",
"isSubtle":true,
"wrap":true
}
]
}
]
},
{
"type":"Container",
"items":[
{
"columns":[
{
"spacing":"small",
"width":"auto",
"verticalContentAlignment":"Center",
"type":"Column",
"selectAction":{
"targetElements":[
"fields-content",
"showFields",
"hideFields"
],
"type":"Action.ToggleVisibility",
"title":"expand"
},
"items":[
{
"type":"TextBlock",
"id":"showFields",
"horizontalAlignment":"Left",
"color":"Accent",
"text":"Show fields",
"wrap":true
},
{
"type":"TextBlock",
"id":"hideFields",
"horizontalAlignment":"Left",
"color":"Accent",
"text":"Hide fields",
"wrap":true,
"isVisible":false
}
]
}
],
"type":"ColumnSet"
},
{
"id":"fields-content",
"isVisible":false,
"type":"Container",
"items":[
{
"type":"FactSet",
"facts":[
{
"title":"title",
"value":"value"
}
]
}
]
}
]
}
]
}
}
]
}
Currently we don't have the sample code in nodejs.Agree with you problem in using node library. I too tested with your payload.
I'm trying to achieve the following. My input JSON looks like this,
{
"data":{
"shipping_address":[
{
"cust_id":"CUST-123",
"street":"123 Main St",
"city":"Atlanta",
"state":"GA",
"zip":"12345"
},
{
"cust_id":"CUST-456",
"street":"456 Front St",
"city":"Philadelphia",
"state":"PA",
"zip":"23456"
}
],
"orders":[
{
"cust_id":"CUST-456",
"items":[
{
"quantity":"2",
"item_code":"ABC-111-222",
"cust_id":"CUST-456"
},
{
"quantity":"1",
"item_code":"DEF-999-01-001",
"cust_id":"CUST-456"
}
]
},
{
"cust_id":"CUST-123",
"items":[
{
"quantity":"10",
"item_code":"998-111-222",
"cust_id":"CUST-123"
}
]
}
],
"payment":[
{
"cust_id":"CUST-123",
"type":"VISA",
"card_no":"1234-1111-2222-3333",
"expiry":"06/2016",
"billing_add_same_as_shipping":"Y",
"first_name":"John",
"last_name":"Smith"
},
{
"cust_id":"CUST-456",
"type":"VISA",
"card_no":"5678-4444-8877-5544",
"expiry":"08/2016",
"billing_add_same_as_shipping":"N",
"first_name":"Steve",
"last_name":"Jones"
}
],
"billing_address":[
{
"cust_id":"CUST-456",
"street":"7788 Back St",
"city":"Gainesville",
"state":"FL",
"zip":"33444"
}
]
}
}
I would like to flatten out this json into two separate jsons
{
"data":{
"shipping_address":{
"cust_id":"CUST-456",
"street":"456 Front St",
"city":"Philadelphia",
"state":"PA",
"zip":"23456"
},
"orders":{
"cust_id":"CUST-456",
"items":[
{
"quantity":"2",
"item_code":"ABC-111-222",
"cust_id":"CUST-456"
},
{
"quantity":"1",
"item_code":"DEF-999-01-001",
"cust_id":"CUST-456"
}
]
},
"payment":{
"cust_id":"CUST-456",
"type":"VISA",
"card_no":"5678-4444-8877-5544",
"expiry":"08/2016",
"billing_add_same_as_shipping":"N",
"first_name":"Steve",
"last_name":"Jones"
},
"billing_address":{
"cust_id":"CUST-456",
"street":"7788 Back St",
"city":"Gainesville",
"state":"FL",
"zip":"33444"
}
}
}
and
{
"data":{
"shipping_address":{
"cust_id":"CUST-123",
"street":"123 Main St",
"city":"Atlanta",
"state":"GA",
"zip":"12345"
},
"orders":{
"cust_id":"CUST-123",
"items":[
{
"quantity":"10",
"item_code":"998-111-222",
"cust_id":"CUST-123"
}
]
},
"payment":{
"cust_id":"CUST-123",
"type":"VISA",
"card_no":"1234-1111-2222-3333",
"expiry":"06/2016",
"billing_add_same_as_shipping":"Y",
"first_name":"John",
"last_name":"Smith"
}
}
}
Is there an easy way in Ruby to perform this without any looping/parsing each fragment of the input json (i.e. by doing any JSON Mapping)?
This is my current solution
Note: my input is a POJO from Java where evaluationTarget contains the input JSON
def json_flattening(input)
customer_order_hash = Hash.new
orders_data = input.evaluationTarget
orders_data.keys.each do |orders_keys|
orders_data[orders_keys].each do |orders_keys_data|
if !customer_order_hash.has_key?(orders_keys_data['cust_id']) then
each_order_hash = Hash.new
customer_order_hash[orders_keys_data['cust_id']] = each_order_hash
end
customer_order_hash[orders_keys_data['cust_id']][orders_keys] = orders_keys_data
end
end
customer_order_hash.keys.each do |cust_id|
puts customer_order_hash[cust_id]
end
end
{"shipping_address"=>{"cust_id"=>"CUST-123", "street"=>"123 Main St", "city"=>"Atlanta", "state"=>"GA", "zip"=>"12345"}, "orders"=>{"cust_id"=>"CUST-123", "items"=>#<Java::NetSfJson::JSONArray:0x69522a14>}, "payment"=>{"cust_id"=>"CUST-123", "type"=>"VISA", "card_no"=>"1234-1111-2222-3333", "expiry"=>"06/2016", "billing_add_same_as_shipping"=>"Y", "first_name"=>"John", "last_name"=>"Smith"}}
{"shipping_address"=>{"cust_id"=>"CUST-456", "street"=>"456 Front St", "city"=>"Philadelphia", "state"=>"PA", "zip"=>"23456"}, "orders"=>{"cust_id"=>"CUST-456", "items"=>#<Java::NetSfJson::JSONArray:0x40030597>}, "payment"=>{"cust_id"=>"CUST-456", "type"=>"VISA", "card_no"=>"5678-4444-8877-5544", "expiry"=>"08/2016", "billing_add_same_as_shipping"=>"N", "first_name"=>"Steve", "last_name"=>"Jones"}, "billing_address"=>{"cust_id"=>"CUST-456", "street"=>"7788 Back St", "city"=>"Gainesville", "state"=>"FL", "zip"=>"33444"}}
I have a laravel collection like the below:
[
{
"id":2,
"name":"Product 1",
"awards":[
{
"id":1,
"name":"Award 1",
"pivot":{
"product_id":2,
"award_id":1
}
},
{
"id":2,
"name":"Award 2",
"description":"Quae sint vero id iste.",
"pivot":{
"product_id":2,
"award_id":2
}
},
{
"id":3,
"name":"Award 3",
"pivot":{
"product_id":2,
"award_id":3
}
},
]
},
{
"id":3,
"name":"Product 2",
"awards":[
{
"id":2,
"name":"Award 2",
"pivot":{
"product_id":3,
"award_id":12
}
},
{
"id":3,
"name":"Award 3",
"pivot":{
"product_id":3,
"award_id":13
}
},
{
"id":14,
"name":"Award 4",
"pivot":{
"product_id":3,
"award_id":14
}
},
]
}
]
Is there a way I can get a collection like the following, all awards, no duplicates:
"awards":[
{
"id":1,
"name":"Award 1",
"pivot":{
"product_id":2,
"award_id":1
}
},
{
"id":2,
"name":"Award 2",
"description":"Quae sint vero id iste.",
"pivot":{
"product_id":2,
"award_id":2
}
},
{
"id":3,
"name":"Award 3",
"pivot":{
"product_id":2,
"award_id":3
}
},
{
"id":12,
"name":"Award 2",
"pivot":{
"product_id":3,
"award_id":12
}
},
{
"id":14,
"name":"Award 4",
"pivot":{
"product_id":3,
"award_id":14
}
},
]
I'm aware that the Laravel collection class has a number of methods (like filter etc) but I'm struggling to get them to work 'across objects' – for example here I have two objects that I almost want to
combine('awards')->unique()
...Kind of thing.
Edit
I'm getting the initial array pretty simply, a box contains a number of products and the products have awards, so I'd like to say, collectively the box has x, y, z award. Anyway, here is the query (the above is the result of return $box):
$box = Box::with('products.awards')->find($id);
There's real simple way to do it.
$awardsArray = $products->lists('awards');
$awardsDirty = new Collection($awardsArray);
$awards = $awardsDirty->unique();
After version of Laravel 5.2, the collection->lists() have been marked as a deprecated method. For the alternative solution will be:
$awards = collect($products)
->pluck("awards")
->flatten(1)
->unique("id");
This is the best way I can think of:
$awards = new \Illuminate\Database\Eloquent\Collection;
foreach($products as $product){
$awards = $awards->merge($product->awards);
}
The nice thing about merge and Eloquent collections in general is that they use the id as unique identifier so your duplicates will be eliminated automatically.
I'm using ActiveRecord with Sinatra. I have AR relation Post has_many Comments.
I need to create response in JSON that returns all posts and their comments. It should look like this:
[
{
"id":1,
"title:"Title_1",
"comments":[
{ "content":"lorem ipsum", "post_id":1 },
{ "content":"foo bar", "post_id":1 },
]
},
{
"id":2,
"title:"Title_2",
"comments":[
{ "content":"lorem ipsum", "post_id":2 },
{ "content":"foo bar", "post_id":2 },
]
}
]
I think it common task to create response like that, so I hope there should be some nice way to do it.
My temporary solution (the code below) works correctly but it too long and unreadable:
Post.all.map{|x| x.as_json(include: [:comments]).values[0] }.to_json
This is another solution that I found:
Post.all.as_json(include: [:comments]).to_json
Sadly, the returned structure looks different, it wraps every post into additional node "post: {}". I'd like to avoid it.
[
{
"post":{
"id":1,
"title:"Title_1",
"comments":[
{ "content":"lorem ipsum", "post_id":1 },
{ "content":"foo bar", "post_id":1 },
]
}
},
{
"post":{
"id":1,
"title:"Title_2",
"comments":[
{ "content":"lorem ipsum", "post_id":2 },
{ "content":"foo bar", "post_id":2 },
]
}
}
]
try:
ActiveRecord::Base.include_root_in_json = false
http://apidock.com/rails/ActiveRecord/Serialization/to_json
I'm trying to get a jsTree working with on demand loading of subnodes. My code is this:
jQuery('#introspection_tree').jstree({
"json_data" : {
"ajax" : {
url : "http://localhost/introspection/introspection/product"
}
},
"plugins" : [ "themes", "json_data", "ui" ]
});
The json returned from the call is
[
{
"data": "Kit 1",
"attr": {
"id": "1"
},
"children": [
[
{
"data": "Hardware",
"attr": {
"id": "2"
},
"children": [
]
}
],
[
{
"data": "Software",
"attr": {
"id": "3"
},
"children": [
]
}
]
]
}
.....
]
Each element could have a lot of children, the tree is going to be big. Currently this is loading the whole tree at once, which could take some time. What do I have to do to implement on-demand-loading of child-nodes when they are opened by the user?
Thanks in advance.
Irishka pointed me in the right direction, but does not fully resolve my problem. I fiddled around with her answer and came up with this. Using two different server functions is done only for clarity. The first one lists all products at top level, the second one lists all children of a given productid:
jQuery("#introspection_tree").jstree({
"plugins" : ["themes", "json_data", "ui"],
"json_data" : {
"ajax" : {
"type": 'GET',
"url": function (node) {
var nodeId = "";
var url = ""
if (node == -1)
{
url = "http://localhost/introspection/introspection/product/";
}
else
{
nodeId = node.attr('id');
url = "http://localhost/introspection/introspection/children/" + nodeId;
}
return url;
},
"success": function (new_data) {
return new_data;
}
}
}
});
The json data returned from the functions is like this (notice the state=closed in each node):
[
{
"data": "Kit 1",
"attr": {
"id": "1"
},
"state": "closed"
},
{
"data": "KPCM 049",
"attr": {
"id": "4"
},
"state": "closed"
},
{
"data": "Linux BSP",
"attr": {
"id": "8"
},
"state": "closed"
}
]
No static data is needed, the tree is now fully dynamic on each level.
I guess it would be nice to display by default first level nodes and then the children will be loaded on demand. In that case the only thing you have to modify is to add "state" : "closed" to the nodes whose child nodes are going to be loaded on demand.
You might wish to send node's id in ajax call so you modify your code
"json_data": {
//root elements to be displayed by default on the first load
"data": [
{
"data": 'Kit 1',
"attr": {
"id": 'kit1'
},
"state": "closed"
},
{
"data": 'Another node of level 1',
"attr": {
"id": 'kit1'
},
"state": "closed"
}
],
"ajax": {
url: "http://localhost/introspection/introspection/product",
data: function (n) {
return {
"nodeid": $.trim(n.attr('id'))
}
}
}
}
From jsTree documentation
NOTE:
If both data and ajax are set the initial tree is rendered from the data string. When opening a closed node (that has no loaded children) an AJAX request is made.
you need to set root elements as tree data on page load and then you will be able to retrieve their children with an ajax request
$("#introspection_tree").jstree({
"plugins": ["themes", "json_data", "ui"],
"json_data": {
//root elements
"data": [{"data": 'Kit 1', "attr": {"id": 'kit1'}} /*, ... */], //the 'id' can not start with a number
"ajax": {
"type": 'POST',
"data": {"action": 'getChildren'},
"url": function (node) {
var nodeId = node.attr('id'); //id="kit1"
return 'yuorPathTo/GetChildrenScript/' + nodeId;
},
"success": function (new_data) {
//where new_data = node children
//e.g.: [{'data':'Hardware','attr':{'id':'child2'}}, {'data':'Software','attr':{'id':'child3'}}]
return new_data;
}
}
}
});
See my answer to a similar question here (the old part) for more details
I spended hours on this problem. Finally i got it that way:
$("#resourceTree").jstree({
"types": {
"default": {
"icon": "fa fa-folder-open treeFolderIcon",
}
},
"plugins": ["json_data", "types", "wholerow", "search"],
"core": {
"multiple": false,
"data": {
"url" : function(node){
var url = "rootTree.json";
if(node.id === "specialChildSubTree")
url = "specialChildSubTree.json";
return url;
},
"data" : function(node){
return {"id" : node.id};
}
}
},
});
rootTree.json:
[
{
"text": "Opened root folder",
"state": {
"opened": true
},
"children": [
{
"id" : "specialChildSubTree",
"state": "closed",
"children":true
}
]
}
]
specialChildSubTree.json:
[
"Child 1",
{
"text": "Child 2",
"children": [
"One more"
]
}
]
So i mark the node that become the parent of the ajax loaded subtree with an id, i watch for in the core configuration.
NOTE:
That node must have the "state" : "closed" parameter and it must have
the parameter "children" : true.
I am using jsTree.js in version 3.3.3
Above solution is all fine. Here I am also providing similar working solution and very simple for lazy loading of nodes using ajax call vakata. When your API works like
https://www.jstree.com/fiddle/?lazy
and for getting any child nodes
https://www.jstree.com/fiddle/?lazy&id=2
for explanation and for complete solution you can have a look at https://everyething.com/Example-of-jsTree-with-lazy-loading-and-AJAX-call
<script type="text/javascript">
$(function () {
$('#SimpleJSTree').jstree({
'core' : {
'data' : {
'url' : "https://www.jstree.com/fiddle/?lazy",
'data' : function (node) {
return { 'id' : node.id };
}
}
}
});
});
</script>