Update deeply nested react redux state array element - javascript

I have a redux state array like this
[{
client_id:12,
template:{
item1:[],
item2:[],
simple templates:[
"Some paragraph 1",
"Some paragraph 2",
"Some paragraph 3",
]
}
}]
So I want to update an element on the simple templates array using redux immutability helpers https://reactjs.org/docs/update.html. For example I want to update "Some paragraph 2" with "Some paragraph #2". I'm passing the data I want to update using a form to the reducers.
So far I have been trying something like this
case TEMP_UPDATE_TEMPLATE: {
console.log('index', action.payload.index);
console.log('data', action.payload.data); //new data that I want to update
return update(state.simple_templates, {
[0]: {
template: {
"Simple Templates": {
[action.payload.index] : {
$set: action.payload.data
}
}
}
}
})
}
It's really confusing for me. Please help me to understand how to update an element of deeply nested object array with a given index.

Try to use $splice instead of $set as it is an array.
return update(state.simple_templates, {
[0]: {
template: {
"simple templates": {
$splice: [action.payload.index, 1, action.payload.data]
}
}
}
})

Related

How to add specific data to nested children in he-tree-vue javascript library

The following is an example of an array of objects, where the data consists of four levels of nested data.
here I display the children's data on the he-tree-vue when the user presses the toggle on a specific element then makes a request to the api, so later the data is added to a certain array value based on existing data to be displayed as child data.
[{ // class
ClassID:"0ede11",
Title:"Mandiri",
children:[{ // course/subject
CourseID:"0ec2",
Title:"Math",
children:[ // chapter
{
ChapterId:"0ss23",
Title:"Test test",
},
{
ChapterId:"0ss23",
Title:"Test test"
},
{
ChapterId:"0se22",
Title:"Test test"
},
]
},
{
CourseID:"rere43",
Title:"History",
children:[
{
ChapterId:"0sse56",
Title:"Test test",
},
{
ChapterId:"0ss2qqq3",
Title:"Test test"
},
{
ChapterId:"0sefg22",
Title:"Test test"
},
]
}
]
}]
how do I add data to specific children, here I use the he-tree-vue library to display a data tree that can be dragged.
now i use the following code, but it only works on the first child only.
getChapter(id, index) {
this.API.getChapter(id, (data) => {
console.log(data);
// I'm still confused in this part, how to dynamically add data to specific child data at each level
const newData = [...this.playlistData];
newData[index].children[index].children = data;
this.playlistData = newData;
},
(err) => {
console.log(err);
});
}
Thank you.
Ok solved, I just need to save each index on each level then use it when going to add data.

Bind data to component with Vuex

I'm new to vue.js and I'm trying to use vuex. Here is my issue:
I have a list of articles (which is a component) linked with a store with v-for="article in articles and a computed property:
computed: {
articles() {
return this.$store.state.articles
}
}
So here is the data in my store:
state: {
articles: [{
title: "Article 1",
id: 1,
description: "Article 1",
}, {
title: "Article 2",
id: 2,
description: "Article 2",
}
}]
}
When I click on an article, I want it to redirect to the article page template (which is a component) with <router-link :to="{path: '/article/'+article.id}"></router-link>.
What I'm trying to do is bind the data of the correct article in the articlePage template.
The issue is that if I apply the same computed property to my articlePage.vue component with a v-for, I will display all of the article on the same page. I would like to display only the matching id component.
How can I do that?
Thank you for your time :)
From your comments I understand that you use vue-router module
So in your routes.js (or structure ) your must have something like this
const router = new VueRouter({
routes: [
{ path: '/articles', component: articlesPage },
{ path: '/article/:id', component: articlePage }
]
})
Then in your articlePage component you can extract ":id" like this:
this.$route.params.id
because vue-router gives you access to the object $route with methods and properties
Check more here https://router.vuejs.org/guide/essentials/dynamic-matching.html
then you can use it to search the articles array and find the data and present them
e.x.
computed:{
selectedArticle(){
var article_id = this.$route.params.id;
var articles = this.$store.state.articles;
var article = null;
for(var a=0;a<articles.length;a++){
if(articles[a].id == article_id ){
article = articles[a];
break;
}
}
return article;
}
}

Populating kendo-tree using from Json

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.

Knockoutjs mapping doesn't work

This is my http://jsfiddle.net/ENMGp/468/ sample code
My Json object
{
"VehicleModels":[
{
"Name":"Model 1",
"Model":{
"MakeName":"Ford"
},
"Styles":[
{
"StockImage":"http://google.com"
}
]
},
{
"Name":"Model 2",
"Model":{
"MakeName":"Ford"
},
"Styles":[
{
"StockImage":"http://bing.com"
}
]
}
]
}
I want to access Styles array, but my viewmodel doesn't allow me to access
Right now your Styles properties is array, you can access it by Styles()[0].StockImage
Here is the working version for object: http://jsfiddle.net/ysN4m/
And here is the working version for array: http://jsfiddle.net/c6Qvq/
And the other changes is, use <span></span> instead of <span />

Using jQuery removeData() with nested data

I'm using the jQuery data() function to store data on a series of divs in a format similar to:
{
options: {
example: {
option_1: {
value: "example 1"
},
option_2: {
value: "example 2"
}
}
}
}
I can add new keys and update the data, e.g.
$("#mydiv").data('options',{'example':{} }); // the object is already created in the live version
$("#mydiv").data('options')['example']['option_3'] = { value: "example 3" };
But when I come to use removeData(), FireBug tells me that the key is undefined, e.g.
$("#mydiv").removeData('options')['example']['option_2'];
Any help appreciated!
.removeData(name) removes the previously stored data with the given name, and returns a jQuery object. In your scenario, you don't want the remove the entire options object, just a specific property of it, so you should be using delete instead:
delete $("#mydiv").data('options')['example']['option_2'];

Categories