knockout: extending mapping to complex JSON - javascript

I receive a complex JSON from the server. Let it be next:
var data = [{
name: "name1",
items:[
{
name:"name11",
subItems:[{
name:"name111",
children[
{id:1,name:"child1111",status:"good"},
{id:2,name:"child1112",status:"bad"},
{id:3,name:"child1113",status:"good"}
]},
{
name:"name112",
children[
{id:4,name:"child1121",status:"good"}]
}]
},
{
name:"name12",
subItems:[{
name:"name121",
children[
{id:5,name:"child1211",status:"bad"}]
}]
}]
},
{
name: "name2",
items:[
{
name:"name21",
subItems:[{
name:"name111",
children[
{id:7,name:"child2111",status:"good"}
]}]
}]
}];
So I have the list of objects each one contains name and items properties. Items is property of the similar list of objects each one contains name and subItems properties. subItems property same to previous and has name and children properties. children is list of my entities. I use mapping for filling my ViewModel.
First of all I can't image how to set as key id in my entity. I am wondering how to "dive" to it. Moreover, I need to extend my entity. Add the compute property like next example:
computProp: ko.computed(function() {return name+status;})
I don't want to create js classes, because I don't see benefits of mapping on this case. I can implement manual mapping in this case. It would be more clear for me.
So any idea, suggesting or critics are welcome.
PS: I have searched/read similar topics

You must explicit declare the children viewmodel to get this behaviour, but you still benefit from getting all the mapping done
http://jsfiddle.net/uXMhA/
ChildViewModel = function(data) {
ko.mapping.fromJS(data, {}, this);
this.computProp = ko.computed(function() {
return this.name() + this.status();
}, this);
};

Related

Creating Dynamic Keys In Object

I am struggling to create dynamic nested keys in javascript. My problem is that I need to have a object like this
{
"grandGrandFather": 'A',
"firstGrandFather": {
name: "AA",
children: {
first: 'AAA',
children: {
first: "AAAA"
}
}
},
"secondGrandFather": {
name: "AB",
first: 'ABA',
children: {
first: "ABAA",
second: "ABAB"
}
}
},
"thirdGrandFather": {
name: "AC",
children: {
name: "ACA"
}
}
}
Here problem is that I need to fetch these data from somewhere and I need to create these values dynamically. The prop creation begins from the first level and goes upto fourth level. So my question is how can I create dynamic keys in JS. Also I know you can create dynamic keys in JS like this:
var obj = {
prop1: "a",
prop2: "b",
prop3:'c'
}
obj['prop4'] = 'd';
Also I have been successful in creating a props to a level but when I need to stack these I get confused any help would be appreciated.
Further details about above object
In the above object I created I am getting data from database and I need to add firstGrandFather, secondGrandFather, thirdGrandFather dynamically. Also I don't know what their children props I need to define would be in the object. Some may have spouse,age,work props inside some may not also I don't know how many of these I would get. And these goes on for one or two more level.
In php it would be easy to create these in associative array easily but I am having hard time doing it in JS.
dynamic keys are possible in ES6+ Docs here
Basically, the syntax is:
obj[variable] = value;
Variable must contain a primitive value.
As for stacking, I'm afraid you have to get used to working with deep keys access with either dot or bracket notation. You can also assign a property of your object to a variable and then access its props.
So if obj is the object from your example:
const firstGrandfathersChildren = obj.firstGrandFather.children
It will have the following assigned:
{
first: 'AAA',
children: {
first: "AAAA"
}
}

Manipulating objects in an array

I am new to JavaScript and been struggling to combine objects in the same array.
Here is what I have:
var testList = [{
'taskList1': 'task1 for taskList1',
},
{
'taskList1': 'task2 for taskList1',
},
{
'taskList2': 'task1 for taskList2'
},
{
'taskList2': 'task2 for taskList2'
}]
The array below is what I really want to get from above:
var testList = [{
'taskList1': 'task1 for taskList1',
'taskList2': 'task1 for taskList2'
},
{
'taskList1': 'task2 for taskList1',
'taskList2': 'task2 for taskList2'
}]
Could anyone please help me to transform my current array into the one above?
Thank you in advance.
Your data structure is quite inefficient in this case. I'd suggest to make it better by having the same array of objects, but each object should contain itemName and belongsTo as a reference to any collection (in your case - a taskList) you may pass there.
Here's a solution to your problem with a more flexible data structure on Codepen - https://codepen.io/Inlesco/pen/dReYgd
I've also added the restructured array of tasks below as an example that's used in the Codepen above.
var testList = [{
item: 'task1',
belongsTo: 'taskList1'
},
{
item: 'task2',
belongsTo: 'taskList1'
},
{
item: 'task1',
belongsTo: 'taskList2'
},
{
item: 'task2',
belongsTo: 'taskList2'
}]
There are many ways to approach this problem. I've just added probably the simplest one.
You can use a for statement to regroup objects with the same taskList ID in one object.
And of course your need to use the right conditions for that.
But the best way is as #Denialos said, to modify your data structure.
Per my comments above to the question, your desired data structure appears to be inverted, or "inside out". Given a list of items, and a set of tasks for each item, I would expect the outer element to be the list, and the inner element to be the set of tasks.
Given that, given your (current) input data I would use:
function restructure(taskList) {
var result = {};
for (var i = 0, n = taskList.length; i < n; ++i) {
// read current item
var item = taskList[i];
var key = Object.keys(item)[0];
var value = item[key];
// update the output
result[key] = result[key] || [];
result[key].push(value);
}
return result;
}
with resulting output:
{
taskList1: [ 'task1 for taskList1', 'task2 for taskList1' ],
taskList2: [ 'task1 for taskList2', 'task2 for taskList2' ]
}
That said, your input data model is also somewhat malformed, with each array element having an unknown key. You should look at what's actually producing that data and fix that if possible.

How to update the value of a single property within a state object in React.js?

So I have the following object structure:
const SamplePalette = {
id: 1,
name: "Sample Palette",
description: "this is a short description",
swatches: [
{
val: "#FF6245",
tints: ["#FFE0DB", "#FFA797"],
shades: ["#751408", "#C33F27"]
},
{
val: "#FFFDA4",
tints: ["#FFFFE1"],
shades: ["#CCCB83"]
},
{
val: "#BFE8A3",
tints: ["#E7FFD7"],
shades: ["#95B77E"]
}
]
}
Let's imagine that this object is managed by the state of my app like this:
this.state = {
currentPalette: SamplePalette,
}
My question is how would I go about updating the val property of a given swatch object in the swatches array? Or more generally - how do I only update pieces of this object?
I tried using the update helper as well as to figure out how Object.assign() works, however I've been unsuccessful and frankly can't really grasp the syntax by just looking at examples.
Also, since I'm going to be modifying this object quite a lot, should I look into maybe using Redux?
[EDIT]
I tried #maxim.sh suggestion but with no success:
this.setState(
{ currentPalette: {...this.state.currentPalette,
swatches[0].val: newValue}
})
Consider you have new new_swatches
I think the clearer way is to get array, update it and put back as:
let new_swatches = this.state.currentPalette.swatches;
new_swatches[0].val = newValue;
this.setState(
{ currentPalette:
{ ...this.state.currentPalette, swatches: new_swatches }
});
Also you have : Immutability Helpers or https://github.com/kolodny/immutability-helper
Available Commands
{$push: array} push() all the items in array on the target.
{$unshift: array} unshift() all the items in array on the target.
{$splice: array of arrays} for each item in arrays call splice() on the target with the parameters provided by the item.
{$set: any} replace the target entirely.
{$merge: object} merge the keys of object with the target.
{$apply: function} passes in the current value to the function and updates it with the new returned value.

ReactJS setting unique keys for resortable list elements

I'm creating a list GUI which can be re-arranged by drag and drop. Data comes from an existing API as an array of objects such as:
var dataFromApi = [
{name: 'jack', label: 'Test element'},
{name: 'john', label: 'Test element 2'}
];
There are many more properties per object, but there is no unique ID field for any object. The nature of data means that duplicate objects are permitted.
I used a React class to render these as a list:
var List = React.createClass({
getDefaultProps: function() {
return {
data: []
};
},
getInitialState: function() {
return {
data: this.props.data
};
},
render: function() {
return (
<ul>
{
this.state.data.map(function(item, idx) {
return (
<li>{item.name}</li>
);
})
}
</ul>
);
}
});
I tried adding some drag-and-drop code, to allow the list to be re-ordered and the state to be updated accordingly. However, to re-order I need each <li key={something?}> element to have a unique key attribute which isn't the index.
What would be the best way add a unique key to each element, but not have this key in the data if I ever needed to send the changes up to a parent element - such as for saving the data to the server.
try doing both, <li key=idx+item> think that would solve your problem
Tried almost everything, setting the key as a combination of item properties and index, but nothing seemed to work if I wanted to allow re-arranging of child elements.
In the end I generated a random key for each object just after an API call which worked and allowed items to be re-arranged.

Backbone: Order of models inside a collection

We created a Collection of models from an array as given below. Our question is: will the Collection preserve the same order of elements/models as it was present in the original array? In other words, is the same order (of source array) guaranteed in Collection?
var colorsData = [
{
name: 'red'
},
{
name: 'blue'
},
{
name: 'green'
},
.....
.....
.....
//other colors
];
var Color = Backbone.Model.extend({
defaults: {
name: 'white'
}
});
var ColorCollection = Backbone.Collection.extend({
model: Color
});
var colorCollection1 = new ColorCollection(colorsData); //creating a collection from the source array colorsData.
From all that I can gather, yes a Collection preserves the original order of elements.
You can read the annotated source for collection to see for yourself that it isn't magically shuffled time to time. Such functions as at, unshift, pop, push, etc. are quite clear indications of this.
You can read the annotated source for parse, which is used to parse the response from server after for example fetch -oprations:
parse: function(resp, xhr) {
return resp;
},
To ascertain that whatever is passed on to your collection won't be shuffled anywhere. The resp will be passed on to the add -function that will process the response in natural order.
As stated in http://backbonejs.org/#Collection
collection.at(index) retrieves models in insertion order.

Categories

Resources