Populating kendo-tree using from Json - javascript

I am in Angular environment using Kendo. All I want to do is following:
Take Json
Produce Kendo tree using it
I have tried it with simple data and it seems to work fine. But this time I have somewhat complex data and it seems like it does not work well with complex Json. I have been trying to have it render Json but it seems like it keeps on thinking and never comes back. I have created a sample Dojo for reference:
http://dojo.telerik.com/EdOqE
I am not sure what am I doing wrong but it just does not seem to work. Can anyone help me with this please?

I presume you have controll over the resultant json, because you'll have to change it a little to fit the TreeView's expected format. Check this out:
{
"items": [{ // Projects
"Id": 0,
"Name": "Your Example Project",
"CreatedOn": "",
"hasChildren": true,
"items": [{ // Analyses
"Id": 0,
"Name": "1.0 - Your Example Run",
"CreatedOn": "",
"hasChildren": true,
"items": [{ // Samples
"Id": 0,
"Name": "Sample 1",
"hasChildren": false,
"Description": "ample frample sample"
}, {
"Id": 0,
"Name": "Sample 2",
"hasChildren": false,
"Description": null
}]
}]
}]
};
The above json is what I did to work in the widget. First of all, the collection properties were renamed to items. All of them, in all levels. With that, kendo will know how property it should deal with. A hasChildren property was added to let it know when it has to show the expand icon. Otherwise it will show the expand option even if the item doesn't haves any children. So user clicks it and get an empty result.
This is the widget initialization options:
{
dataSource: new kendo.data.HierarchicalDataSource({
data: things,
schema: {
data: "items"
}
}),
dataTextField: "Name"
};
With schema.data I tell which property kendo will deal as the collection item. The dataSource expects an array, but if you give him an object, you have to set this property. If it was an array, then kendo would look for item property of each child for default. dataTextField is the name of the property it will use as the label.
Demo
Here is another demo with the data as an array. No need to set schema.data.
Update:
I was afraid you would say that. Yes, there is a way to deal with the data if you can't change it in the server-side. You have to intercept the data at the schema.parse() method and change the resultant data object property to items, so then the widget will understand:
schema: {
data: "items",
parse: function(data) {
if (data.hasOwnProperty("Projects")) {
return { items: data.Projects };
}
else if (data.hasOwnProperty("Analyses")) {
return { items: data.Analyses };
}
else if (data.hasOwnProperty("Samples")) {
return { items: data.Samples };
}
}
}
Demo
Every node when opened will call parse with items collection as data parameter. You have to return a new object with the property name as items instead of Projects, Analysis or Samples.
I forgot you can't touch the data, so can't add hasChildren property as well. Then you have to add a tiny logic into parse to set those properties in each level, otherwise the expand icon would not appear:
schema: {
data: "items",
parse: function(data) {
if (data.hasOwnProperty("Projects")) {
data.Projects.forEach(p => {
p.hasChildren = false;
if (p.hasOwnProperty("Analyses")) {
p.hasChildren = true;
}
});
return { items: data.Projects };
}
else if (data.hasOwnProperty("Analyses")) {
data.Analyses.forEach(a => {
a.hasChildren = false;
if (a.hasOwnProperty("Samples")) {
a.hasChildren = true;
}
});
return { items: data.Analyses };
}
else if (data.hasOwnProperty("Samples")) {
return { items: data.Samples };
}
}
}
Demo
It is ugly, I know. But get used to Kendo, it is the it goes with it.

Related

google docs api documents.get multiple fields ? (nodejs)

How can I select multiple fields when using the documents.get ?
Right now I am getting the documenmt like this:
const doc = await docs.documents.get({
documentId: copiedFile.data.id,
fields: 'body/content'
});
which returns this:
"data": {
"body": {
"content": [...]
}
}
However, I need to also get the inlineObject and the only way so far I have been able to do so, is by removing the fields proeprty completely
const doc = await docs.documents.get({
documentId: copiedFile.data.id,
});
Then I get this:
"data": {
"title": "Some document title",
"body": {
"content": [...]
},
"headers": {
},
"footers": {
},
"documentStyle": {
},
"namedStyles": {
},
"lists": {
},
"revisionId": "some-long-id",
"suggestionsViewMode": "SUGGESTIONS_INLINE",
"inlineObjects": {
},
"documentId": "some-long-id"
}
But I am really only interested in data.body.content and data.inlineObjects
When selecting everything the response is many thousands of lines of json larger, which I don't want.
I have tried fields: ['body/content', 'inlineObjects'] but that only returns body.content and not the inlineObjects - also the documentation doesn't mention this syntax anywhere, it was just to experiment.
I think it doesn't return any inlineObjects when you don't have any inlineObjects in the document. To confirm if the actual format is working and the statement above is true, try using other fields where a value is confirmed to be returned such as revisionId or title.
Test:
const doc = await docs.documents.get({
documentId: copiedFile.data.id,
fields: 'body/content,inlineObjects'
});
Output:

Update single object in localStorage

I want to update a single Object in my localStorage. I made a detail page, where I can submit new values (progress and value)
When I want to update the value, it changes the value in both objects. How can I change just one object.
Here is my deployment link.(its work in progress)
https://mastery-app.herokuapp.com/
This is my localStorage array:
skills[
{
"title": "Sewing",
"imageSrc": "images.unsplash.com",
"description": "Make your own clothes",
"category": "crafting",
"progress": 500,
"isDone": false,
"rank": 0,
"value": 0
},
{
"title": "Crocheting",
"imageSrc": "images.unsplash.com",
"description": "Interlock loops of yarn",
"category": "crafting",
"progress": 500,
"isDone": false,
"rank": 0,
"value": 0
}
]
This is how I update the localStorage:
const update = skills.map((skills) => {
skills.title === skills.title;
const updateProgress = skills.progress - value;
const rankNumber = parseInt(ranking);
const updateRank = skills.rank + rankNumber;
console.log(updateRank);
const updateValue = skills.value + value;
return {
title: skills.title,
rank: updateRank,
description: skills.description,
progress: updateProgress.toFixed(1),
imageSrc: skills.imageSrc,
category: skills.category,
isDone: false,
value: updateValue,
};
});
localStorage.setItem('skills', JSON.stringify(update));
You may consider using the find method to find the object you want to update. map is not the right function to be used for your use case.
Also skills.title === skills.title; has no effect at all (Maybe you wanted to use an if statement to do some kind of filtering by using title but that always would return true). Please remove that.
Now, I don't exactly know which field are you going to use to search for the object you want to update, but it has to be unique. If none of the fields in the objects are unique you should consider adding an unique id field in the skills objects. But if title is unique you can use the title to search. Then you can do something like the pseudo code below:
const toUpdate = skills.find(skill => skill.title === your_title_here)
toUpdate.field_to_update_1 = some_value_1
toUpdate.field_to_update_2 = some_value_2
localStorage.setItem('skills', JSON.stringify(skills))
Please also check the MDN docs to see how map, find and other array methods work and some of their use cases.

Adding a new object into a nested array

I want to add a new object for each nested array. I'm calling this function any time I add a product to my orderintake:
add2order(productID, productName, productRatePlans) {
this.orderIntake.push({ productID, productName, productRatePlans });
let i = 0;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges.forEach(element => {
i++;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].quantity = this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].defaultQuantity;
});
}
this is an example response from the server:
{
"id": "8adc8f996928b9a4016929c59b943a8f",
"sku": "SKU-00006778",
"Partner_Account_ID__c": null,
"productRatePlans": [
{
"id": "8adce4216928c28d016929c59bff3372",
"status": "Active",
"name": "Enterprise",
"description": null,
"effectiveStartDate": "2016-02-26",
"effectiveEndDate": "2029-02-26",
"productRatePlanCharges": [
{
"id": "8adc8f996928b9a4016929c59d183a92",
"name": "USAGE_COUNTER_2",
"type": "Usage",
"model": "Volume",
"uom": "Each",
"pricingSummary": [
"Up to 5000 Each: USD0 flat fee"
],
"pricing": [
{
...
}
],
"defaultQuantity": null,
"applyDiscountTo": null,
"discountLevel": null,
"discountClass": null,
...
"financeInformation": {
..,
}
}
]
}
],
"productFeatures": [
{
...
}
]
}
The data is being retrived this way from an external REST backend so unfortunately I can't initialize the data including the new property...
so in every productRatePlanCharges there should be 1 new object 'quantity'.
How can I add this field to every productRatePlanCharges?
Right now I'm getting: ERROR
TypeError: Cannot read property 'productRatePlanCharges' of undefined
And how can I make sure I'm always adding this to the last orderIntake element? Don't mind productRatePlans there is only 1 in each orderintake...
thanks for your support!
Here you have to create productDetails object with inititalised array like below so that you won't get the error.
add2order(productID, productName, productRatePlans) {
// Create object like below
let productDetails = { productID : productID, productName : productName, productRatePlans : productRatePlans
}
this.orderIntake.push(productDetails);
let i = 0;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges.forEach(element => {
i++;
this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].quantity = this.orderIntake[0].productRatePlans[0].productRatePlanCharges[
i
].defaultQuantity;
});
}
Hope this will help!
as you used Angular you probably use Typescript too. I recommend that you create a model like your incoming model and there define your quantity: number inside productRatePlanCharges object. then map the incoming data to your own model. therefore you will have a quantity=0 in your model that you can change it later in a loop.
If you want to continue with your own way take a look at this:
Add new attribute (element) to JSON object using JavaScript
there is no problem to add an element to current model almost like you did, and the problem might be somewhere else as your error refers to existence of productRatePlanCharges!
as you used forEach I prefer to use that 'element' and double iterating with i++; is not a good idea to me.
this might be better:
element.quantity = element.defaultQuantity;

How to access object field in server array response?

I made a parse.com get request, the returned data is stored in:
$scope.tastes = data.results
{
"createdAt": "2016-03-16T07:39:15.745Z",
"objectId": "Cmg8GdOv2Z",
"updatedAt": "2016-03-16T07:39:15.745Z",
"user": {
"__type": "Pointer",
"className": "_User",
"objectId": "vYOsndWlto"
},
"userTastes": [
{
"actualite": {
"checked": true
},
"economie": {
"checked": true
},
"entrepreneuriat": {
"checked": false
}
}
]
}
Well, I want to get userTastes array.
I've tried
.success(function (data, status) {
$scope.tastes = data.results.userTastes;
console.log($scope.tastes);
})
However nothing is returned. I think that I'm missing something.
My question : How do I get userTastes in $scope.tastes ?
I writing a separate answer because I believe this needs further explanation and not just the fix to your problem.
You only provided an object response in your question, but apparently you are getting an array response from your server, while you can directly access object fields, on array objects you need to access the position first, Ex:
$scope.objectResponse = {"foo":"bar"};
console.log($scope.objectResponse.foo); // Will print "bar"
in contrast array responses:
$scope.arrayResponse = [{"foo":"bar"}];
console.log($scope.arrayResponse[0].foo); // Will print "bar"
Just make sure you are getting the response you want from your server.
results[0].userTastes work worked perfectly thanks !
If someone have a tutorial link or good course about array and objects in JS because I'm a little bit confused about that.
Have a good day !

KnockoutJs - Pushing to an element in an observable array does not work

I have an object (analysisLogData) that I use to generate a table using KnockoutJS. Here's the viewModel containing this object:
function AppViewModel() {
var self = this;
self.analysisLogData = ko.observableArray();
self.analysisLogTitle = ko.observable("Warnings")
self.changeAnalysisLog = function(title) {
self.analysisLogTitle(title)
}
var data =
{
"Warnings": [
{
"number": 3002,
"description": "There may be a problem with the device you are using if you use the default profile"
},
{
"number": 3001,
"description": "There may be a problem with the device you are using if you don't use the default profile"
}
]
,
"Errors": [
{
"number": 1000,
"description": "No networks are loaded"
},
{
"number": 1002,
"description": "No devices are loaded"
}]
}
self.addLog = function (type, content) {
self.analysisLogData()[type].push(content);
}
self.analysisLogData.push(data)
}
ko.applyBindings(new AppViewModel());
You can see the result here in a JSFiddle: http://jsfiddle.net/etiennenoel/V4r2e/5/
I want to be able to add an error or a warning without losing the warnings or errors already present.
I tried to do the following in the self.addLog function:
self.addLog = function (type, content) {
self.analysisLogData()[type].push(content);
}
but it says that it can't push to an undefined object...
Ok, after playing around in fiddle. I believe that you need to do some changes in how you pushed data in the observable array. But without doing a lot of modification check my solution in this link.
jsfiddle example
self.addLog = function (type, content) {
self.analysisLogData()[0][type].push({
"number": 1002,
"description": content
});
}
And data object should be
"Warnings": ko.observableArray([........]),
"Errors": ko.observableArray([..........])
I did two things
Modify Warnings & Errors to be an Observable Array
I pushed the data in this self.analysisLogData()[0][type].push instead of self.analysisLogData()[type].push
self.analysisLogData() is an array which contains arrays of Errors/Warnings.
I'm not sure if that's how you want your data structured.
To get the fiddle to work you can replace the addLog function with this:
self.addLog = function (type, content) {
self.analysisLogData()[0][type].push(content);
}

Categories