Creating a new object using reduce in JS - javascript
I've been dealing with creating an object with reduce from a nested array.
The object needs to have the _iud keys with the value of initialValue, from the object that contains both keys. I made a function that can iterate through them but can't return the new object with all the new properties I got. I've tried to use the shallow and deep copy to clone acc but can't make it :( Could anyone give me a hand?
This is the nested array
export const formData = [
{
component: 'page',
label: 'Page 1',
_uid: '0c946643-5a83-4545-baea-055b27b51e8a',
fields: [
{
component: 'field_group',
label: 'Name',
_uid: 'eb169f76-4cd9-4513-b673-87c5c7d27e02',
fields: [
{
component: 'text',
label: 'First Name',
initialValue: '2345432',
type: 'text',
_uid: '5b9b79d2-32f2-42a1-b89f-203dfc0b6b98',
},
{
component: 'text',
label: 'Last Name',
initialValue: '2345432',
type: 'text',
_uid: '6eff3638-80a7-4427-b07b-4c1be1c6b186',
},
],
},
{
component: 'text',
label: 'Email',
initialValue: '2345432',
type: 'email',
_uid: '7f885969-f8ba-40b9-bf5d-0d57bc9c6a8d',
},
{
component: 'text',
label: 'Phone',
initialValue: '2345432',
type: 'text',
_uid: 'f61233e8-565e-43d0-9c14-7d7f220c6020',
},
],
},
{
component: 'page',
label: 'Page 2',
_uid: '3a30803f-135f-442c-ab6e-d44d7d7a5164',
fields: [
{
component: 'options',
label: 'Radio Buttons',
type: 'radio',
initialValue: '2345432',
_uid: 'bd90f44a-d479-49ae-ad66-c2c475dca66b',
options: [
{
component: 'option',
label: 'Option 1',
value: 'one',
},
{
component: 'option',
label: 'Option 2',
value: 'two',
},
],
},
{
component: 'text',
label: 'Conditional Field',
type: 'text',
_uid: 'bd90f44a-d479-49ae-ad66-c2c475daa66b',
initialValue: '2345432',
conditional: {
value: 'two',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
},
],
},
{
component: 'page',
label: 'Page 3a',
_uid: 'cd392929-c62e-4cdb-b4dd-914035c1cc8d',
initialValue: '2345432',
conditional: {
value: 'one',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
fields: [
{
component: 'options',
label: 'More radio buttons',
type: 'radio',
_uid: 'a15bef56-ab67-4b98-a781-4441cc3bba56',
initialValue: '2345432',
options: [
{ component: 'option', label: 'Option 1', value: 'one' },
{ component: 'option', label: 'Option 2', value: 'two' },
],
},
],
},
{
component: 'page',
label: 'Page 3b',
_uid: '1dd4ec7c-fb53-47f4-af1b-1ab8f805b888',
conditional: {
value: 'two',
initialValue: '2345432',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
fields: [
{
component: 'options',
label: 'Something to toggle',
type: 'radio',
_uid: '3ca9237d-e225-4950-a298-f81ce996cb85',
options: [
{
component: 'option',
label: 'Option 1',
value: 'one',
},
{ component: 'option', label: 'Option 2', value: 'two' },
],
},
{
component: 'field_group',
label: 'Name',
_uid: 'b8406cb5-ff0d-4a83-a8f8-99740b6d91f7',
fields: [
{
component: 'text',
label: 'First Name',
initialValue: '2345432',
type: 'text',
_uid: 'c6e065e1-dbcb-44ea-831f-ac3af889e964',
},
{
component: 'text',
label: 'Last Name',
initialValue: '2345432',
type: 'text',
_uid: 'e279ba9c-3c9b-4df8-b267-d14b3c2adcdd',
},
],
},
{
component: 'text',
label: 'Email',
initialValue: '2345432',
type: 'email',
_uid: 'a95208a0-7673-48a8-b704-2fb408fa6eec',
},
{
component: 'text',
label: 'Phone',
initialValue: '2345432',
type: 'text',
_uid: '8dde5083-0619-42d6-8fc7-0563c35d03ad',
},
],
},
{
component: 'page',
label: 'Page 4',
_uid: '0c946643-5a83-4545-baea-065b27b51e8a',
fields: [
{
component: 'text',
label: 'Final Comment',
initialValue: '2345432',
type: 'text',
_uid: 'f61231e8-565e-43d0-9c14-7d7f220c6020',
},
],
},
]
The function:
function getInitialValues(formData = []) {
return Array.from(formData).reduce((acc, currentValue, idx) => {
const arrayOfStrings = ['page', 'field_group', 'options']
const str = currentValue.component
const found = arrayOfStrings.find((v) => str === v)
if (found) {
// console.log('entro', currentValue)
getInitialValues(currentValue?.fields)
return acc
}
if (
(currentValue.component === 'text' || currentValue.component === 'select') &&
currentValue.label === 'Conditional Field'
) {
acc[currentValue._uid] = currentValue?.initialValue
return acc
}
return acc
}, {})
}
My expected result is something like this from all the _uids that has initialValues (only for references)
{
5b9b79d2-32f2-42a1-b89f-203dfc0b6b98: '2345432',
5b9b79d2-32f2-42a1-b89f-203dfc0b6b97: '2345431',
5b9b79d2-32f2-42a1-b89f-203dfc0b6b96: '2345430',
}
I find it easier to separate the extraction of your _uid/initialValue properties from the formatting of these into an output object.
Here is a recursive extract function and a simple convert function that builds on it.
const extract = (xs) =>
xs .flatMap (({initialValue, _uid, fields = []}) =>
[[_uid, initialValue], ...extract (fields)]
) .filter (([_, init]) => init != null)
const convert = xs =>
Object .fromEntries (extract (xs))
const formData = [{component: "page", label: "Page 1", _uid: "0c946643-5a83-4545-baea-055b27b51e8a", fields: [{component: "field_group", label: "Name", _uid: "eb169f76-4cd9-4513-b673-87c5c7d27e02", fields: [{component: "text", label: "First Name", initialValue: "2345432", type: "text", _uid: "5b9b79d2-32f2-42a1-b89f-203dfc0b6b98"}, {component: "text", label: "Last Name", initialValue: "2345432", type: "text", _uid: "6eff3638-80a7-4427-b07b-4c1be1c6b186"}]}, {component: "text", label: "Email", initialValue: "2345432", type: "email", _uid: "7f885969-f8ba-40b9-bf5d-0d57bc9c6a8d"}, {component: "text", label: "Phone", initialValue: "2345432", type: "text", _uid: "f61233e8-565e-43d0-9c14-7d7f220c6020"}]}, {component: "page", label: "Page 2", _uid: "3a30803f-135f-442c-ab6e-d44d7d7a5164", fields: [{component: "options", label: "Radio Buttons", type: "radio", initialValue: "2345432", _uid: "bd90f44a-d479-49ae-ad66-c2c475dca66b", options: [{component: "option", label: "Option 1", value: "one"}, {component: "option", label: "Option 2", value: "two"}]}, {component: "text", label: "Conditional Field", type: "text", _uid: "bd90f44a-d479-49ae-ad66-c2c475daa66b", initialValue: "2345432", conditional: {value: "two", field: "3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b"}}]}, {component: "page", label: "Page 3a", _uid: "cd392929-c62e-4cdb-b4dd-914035c1cc8d", initialValue: "2345432", conditional: {value: "one", field: "3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b"}, fields: [{component: "options", label: "More radio buttons", type: "radio", _uid: "a15bef56-ab67-4b98-a781-4441cc3bba56", initialValue: "2345432", options: [{component: "option", label: "Option 1", value: "one"}, {component: "option", label: "Option 2", value: "two"}]}]}, {component: "page", label: "Page 3b", _uid: "1dd4ec7c-fb53-47f4-af1b-1ab8f805b888", conditional: {value: "two", initialValue: "2345432", field: "3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b"}, fields: [{component: "options", label: "Something to toggle", type: "radio", _uid: "3ca9237d-e225-4950-a298-f81ce996cb85", options: [{component: "option", label: "Option 1", value: "one"}, {component: "option", label: "Option 2", value: "two"}]}, {component: "field_group", label: "Name", _uid: "b8406cb5-ff0d-4a83-a8f8-99740b6d91f7", fields: [{component: "text", label: "First Name", initialValue: "2345432", type: "text", _uid: "c6e065e1-dbcb-44ea-831f-ac3af889e964"}, {component: "text", label: "Last Name", initialValue: "2345432", type: "text", _uid: "e279ba9c-3c9b-4df8-b267-d14b3c2adcdd"}]}, {component: "text", label: "Email", initialValue: "2345432", type: "email", _uid: "a95208a0-7673-48a8-b704-2fb408fa6eec"}, {component: "text", label: "Phone", initialValue: "2345432", type: "text", _uid: "8dde5083-0619-42d6-8fc7-0563c35d03ad"}]}, {component: "page", label: "Page 4", _uid: "0c946643-5a83-4545-baea-065b27b51e8a", fields: [{component: "text", label: "Final Comment", initialValue: "2345432", type: "text", _uid: "f61231e8-565e-43d0-9c14-7d7f220c6020"}]}]
console .log (convert (formData))
.as-console-wrapper {max-height: 100% !important; top: 0}
The question also seems to imply that you want to do an update of the data. I would think of that as a separate step, which you already seem to be able to do.
The problem is in:
if (found) {
// console.log('entro', currentValue)
getInitialValues(currentValue?.fields)
return acc
}
this call to getInitialValues is supposed to return a result that is not saved into acc.
One way to correct it is to do something like this:
if (found) {
const res = getInitialValues(currentValue.fields);
return Object.assign(acc, res);
}
There may be other issues as well, but this is the one that stood up for me.
Note: two out of three of the uids in the "expected results" do not appear in the first code snippet (the example of formData).
As for the other one (with uid: 5b9b79d2-32f2-42a1-b89f-203dfc0b6b98) it has a label of 'First Name' not 'Conditional Field' - that's why it doesn't show up in the output.
(Full) Corrected code
function getInitialValues (formData = []) {
return formData.reduce((acc, currentValue) => {
const arrayOfStrings = ['page', 'field_group', 'options'];
const str = currentValue.component;
const found = arrayOfStrings.find((v) => str === v);
if (found) {
const res = getInitialValues(currentValue.fields);
return Object.assign(acc, res);
}
if (
(currentValue.component === 'text' || currentValue.component === 'select') &&
currentValue.label === 'Conditional Field'
) {
if (currentValue.initialValue) {
acc[currentValue._uid] = currentValue.initialValue;
}
}
return acc;
}, {});
I found a simple forEach loop with recursion to be easier.
const formData = [{
component: 'page',
label: 'Page 1',
_uid: '0c946643-5a83-4545-baea-055b27b51e8a',
fields: [{
component: 'field_group',
label: 'Name',
_uid: 'eb169f76-4cd9-4513-b673-87c5c7d27e02',
fields: [{
component: 'text',
label: 'First Name',
initialValue: '2345432',
type: 'text',
_uid: '5b9b79d2-32f2-42a1-b89f-203dfc0b6b98',
},
{
component: 'text',
label: 'Last Name',
initialValue: '2345432',
type: 'text',
_uid: '6eff3638-80a7-4427-b07b-4c1be1c6b186',
},
],
},
{
component: 'text',
label: 'Email',
initialValue: '2345432',
type: 'email',
_uid: '7f885969-f8ba-40b9-bf5d-0d57bc9c6a8d',
},
{
component: 'text',
label: 'Phone',
initialValue: '2345432',
type: 'text',
_uid: 'f61233e8-565e-43d0-9c14-7d7f220c6020',
},
],
},
{
component: 'page',
label: 'Page 2',
_uid: '3a30803f-135f-442c-ab6e-d44d7d7a5164',
fields: [{
component: 'options',
label: 'Radio Buttons',
type: 'radio',
initialValue: '2345432',
_uid: 'bd90f44a-d479-49ae-ad66-c2c475dca66b',
options: [{
component: 'option',
label: 'Option 1',
value: 'one',
},
{
component: 'option',
label: 'Option 2',
value: 'two',
},
],
},
{
component: 'text',
label: 'Conditional Field',
type: 'text',
_uid: 'bd90f44a-d479-49ae-ad66-c2c475daa66b',
initialValue: '2345432',
conditional: {
value: 'two',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
},
],
},
{
component: 'page',
label: 'Page 3a',
_uid: 'cd392929-c62e-4cdb-b4dd-914035c1cc8d',
initialValue: '2345432',
conditional: {
value: 'one',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
fields: [{
component: 'options',
label: 'More radio buttons',
type: 'radio',
_uid: 'a15bef56-ab67-4b98-a781-4441cc3bba56',
initialValue: '2345432',
options: [{
component: 'option',
label: 'Option 1',
value: 'one'
},
{
component: 'option',
label: 'Option 2',
value: 'two'
},
],
}, ],
},
{
component: 'page',
label: 'Page 3b',
_uid: '1dd4ec7c-fb53-47f4-af1b-1ab8f805b888',
conditional: {
value: 'two',
initialValue: '2345432',
field: '3a30803f-135f-442c-ab6e-d44d7d7a5164_bd90f44a-d479-49ae-ad66-c2c475dca66b',
},
fields: [{
component: 'options',
label: 'Something to toggle',
type: 'radio',
_uid: '3ca9237d-e225-4950-a298-f81ce996cb85',
options: [{
component: 'option',
label: 'Option 1',
value: 'one',
},
{
component: 'option',
label: 'Option 2',
value: 'two'
},
],
},
{
component: 'field_group',
label: 'Name',
_uid: 'b8406cb5-ff0d-4a83-a8f8-99740b6d91f7',
fields: [{
component: 'text',
label: 'First Name',
initialValue: '2345432',
type: 'text',
_uid: 'c6e065e1-dbcb-44ea-831f-ac3af889e964',
},
{
component: 'text',
label: 'Last Name',
initialValue: '2345432',
type: 'text',
_uid: 'e279ba9c-3c9b-4df8-b267-d14b3c2adcdd',
},
],
},
{
component: 'text',
label: 'Email',
initialValue: '2345432',
type: 'email',
_uid: 'a95208a0-7673-48a8-b704-2fb408fa6eec',
},
{
component: 'text',
label: 'Phone',
initialValue: '2345432',
type: 'text',
_uid: '8dde5083-0619-42d6-8fc7-0563c35d03ad',
},
],
},
{
component: 'page',
label: 'Page 4',
_uid: '0c946643-5a83-4545-baea-065b27b51e8a',
fields: [{
component: 'text',
label: 'Final Comment',
initialValue: '2345432',
type: 'text',
_uid: 'f61231e8-565e-43d0-9c14-7d7f220c6020',
}, ],
},
]
function getInitialValues(formData = [], output=[]) {
formData.forEach(obj => {
// first check for the Conditional Field label
let found = obj.hasOwnProperty('label') && obj.label === "Conditional Field";
// then loop through the component fields if neccesary
if (!found) ['select','text','options'].forEach(val => {
if (obj.hasOwnProperty('component') && obj.component === val) found = true;})
// if found update the output array
if (found) output.push({[obj._uid]: obj.initialValue})
// check for recursion
if (obj.hasOwnProperty('fields')) output = getInitialValues(obj.fields, output)
})
return output;
}
console.log(getInitialValues(formData))
Related
Conditionally Filter Options for References in Sanity IO
I have 3 schema, Menu Section Sub-Section i want to conditionally filter the list of options provided based on the current object. Lets say i want to create a new sub-section which is under Pizza Menu so i will input Menu: Pizza (I created it before) and so section input should only accept and display all the available sections under pizza menu only. Code: subSection.js export default { name: 'sub-section', title: 'Sub-Section', type: 'document', fields: [ { name: 'title', type: 'string' }, { name: 'description', type: 'string' }, { name: 'menu', type: 'reference', to: [{ type: 'menu' }], }, { name: 'section', type: 'reference', to: [{ type: 'section' }], options: { filter: 'menu == references($menu)', // this does not work filterParams: { menu: 'Neopolitan' }, // ^ ^ This is static, cannot reference current object }, }, ], }; section.js export default { name: 'section', title: 'Section', type: 'document', fields: [ { name: 'title', type: 'string' }, { name: 'description', type: 'string' }, { name: 'menu', type: 'reference', to: [{ type: 'menu' }], }, ], }; menu.js export default { title: 'Menu', name: 'menu', type: 'document', fields: [ { title: 'Title', name: 'title', type: 'string', }, ], };
Recursively build an object based on the keys & values from another?
I want to programmatically build a dynamic data object based on a context object, like in the example below. const context = { ...other props..., groups: [ { heading: 'basic', canHaveMultiple: false, // data.basic = {username: { type: 'text', value: '' }, password: { type: 'password', value: ''}} inputs: [ { name: 'username', type: 'text', placeholder: 'username', }, { name: 'password', type: 'password', placeholder: 'password', }, ], }, { heading: 'about', canHaveMultiple: false, // data.about = {about: { type: 'textarea', value: '' }} inputs: [ { name: 'about', type: 'textarea', placeholder: 'about', canHaveMultiple: false, }, ], }, { heading: 'hobbies', canHaveMultiple: true, // data.hobbies = { model: { title: {type: 'text', value: ''}, description: {type: 'textarea', value: ''} }, values: [ { title: {type: 'text', value: ''}, description: {type: 'textarea', value: ''} }] inputs: [ { name: 'title', type: 'text', placeholder: 'about', canHaveMultiple: false, }, { name: 'description', type: 'description', placeholder: null, canHaveMultiple: false, }, ], }, { heading: 'friends', canHaveMultiple: true, // data.friends = { model: {title: {type: 'text', value: '' }, description: { type: 'textarea', value: '' }} }, values: [{ name: {type: 'text', value: ''},hobbies: [{ title: {type: 'text', value: ''}, description: {type: 'textarea', value: ''}} }] } inputs: [ { name: 'name', type: 'text', placeholder: 'this is fine', canHaveMultiple: false }, { name: 'hobbies', type: 'nested', canHaveMultiple: true, inputs: [ { name: 'title', type: 'textarea', placeholder: 'about', canHaveMultiple: false, }, { name: 'description', type: 'textarea', placeholder: 'about', canHaveMultiple: false, }, ] } ], }, ], } The output data should be something like so: data: { basic: { username: { type: 'text', value: '', }, password: { type: 'password', value: '' } }, about: { about: { type: 'textarea', value: '', } }, hobbies: { model: { title: { type: 'text', value: '', }, description: { type: 'textarea', value: '', } }, values: [ { title: { type: 'text', value: '', }, description: { type: 'textarea', value: '', } } ] }, friends: { model: { name: { type: 'text', value: '', }, hobbies: { title: { type: 'text', value: '', }, description: { type: 'textarea', value: '', } } }, values: [ ] }, } In essence, groups[int].heading becomes the top level property of the data object, and each group along with each of the child from inputs has a canHaveMultiple property, which distinguishes whether the resulting object structure will be either: canHaveMultiple == false group.input.name: { group.type, value: '' } OR canHaveMultiple == true { model: { group.input.name: { type: group.input.type, value: '' }, ... etc }, values: [{ group.input[0].name: { type: group.input[0].type, value: '', }, group.input[1].name: { type: group.input[1].type, value: '', } }] } The model is there so that I can easily push a new copy of that object into the values array. So here is my question: Is there a way to recursively do this so that the program will create the data object from the context object, and keep looking down the context object chain for any 'nested' type (also within the inputs array) until there is none left? Is this do-able and efficient or am I thinking and going about this the wrong way? *PS: I have been trying real hard and wrecking my head for a few days now on this but I cannot seem to get it working for Nested Objects beyond 3 levels because I am a newbie in recursion. Please help me :(
This function first group by heading (using reduce) then goes recursively over the inputs fields. That is if an input has inputs we loop that too. const context={groups:[{heading:"basic",canHaveMultiple:!1,inputs:[{name:"username",type:"text",placeholder:"username"},{name:"password",type:"password",placeholder:"password"},]},{heading:"about",canHaveMultiple:!1,inputs:[{name:"about",type:"textarea",placeholder:"about",canHaveMultiple:!1},]},{heading:"hobbies",canHaveMultiple:!0,inputs:[{name:"title",type:"text",placeholder:"about",canHaveMultiple:!1},{name:"description",type:"textarea",placeholder:null,canHaveMultiple:!1},]},{heading:"friends",canHaveMultiple:!0,inputs:[{name:"name",type:"text",placeholder:"this is fine",canHaveMultiple:!1},{name:"hobbies",type:"nested",canHaveMultiple:!0,inputs:[{name:"title",type:"textarea",placeholder:"about",canHaveMultiple:!1},{name:"description",type:"textarea",placeholder:"about",canHaveMultiple:!1},]}]},]} function transform(arr) { var result = arr.reduce(function(agg, item) { var heading = item.heading var canHaveMultiple = item.canHaveMultiple var parent; agg[heading] = {} if (canHaveMultiple === false) { parent = agg[heading] } if (canHaveMultiple === true) { agg[heading] = { model: {}, values: [] } parent = agg[heading]['model'] } function do_inputs(parent, inputs) { inputs.forEach(function(input) { if (!input.inputs) { parent[input.name] = { type: input.type, value: '' // todo: placeholder and other properties } } else { // nested parent[input.name] = {} do_inputs(parent[input.name], input.inputs) } }) } do_inputs(parent, item.inputs) return agg; }, {}) return result; } console.log(transform(context.groups)); .as-console-wrapper { max-height: 100% !important; }
I have two snippets which might get you most of the way there. The first one is perhaps too simple, ignoring your model/value part. But it should be easy to understand: const convert = (xs) => Object .fromEntries ( xs .map (({name, type, inputs = []}) => [name, inputs .length ? convert (inputs) : {type, value: ''}] ) ) const restructure = (context) => ({ data: Object .fromEntries (context .groups .map ( ({heading, inputs}) => [heading, convert (inputs)] )) }) const context = {other: "props", groups: [{heading: "basic", canHaveMultiple: !1, inputs: [{name: "username", type: "text", placeholder: "username"}, {name: "password", type: "password", placeholder: "password"}]}, {heading: "about", canHaveMultiple: !1, inputs: [{name: "about", type: "textarea", placeholder: "about", canHaveMultiple: !1}]}, {heading: "hobbies", canHaveMultiple: !0, inputs: [{name: "title", type: "text", placeholder: "about", canHaveMultiple: !1}, {name: "description", type: "description", placeholder: null, canHaveMultiple: !1}]}, {heading: "friends", canHaveMultiple: !0, inputs: [{name: "name", type: "text", placeholder: "this is fine", canHaveMultiple: !1}, {name: "hobbies", type: "nested", canHaveMultiple: !0, inputs: [{name: "title", type: "textarea", placeholder: "about", canHaveMultiple: !1}, {name: "description", type: "textarea", placeholder: "about", canHaveMultiple: !1}]}]}]} console .log (restructure (context)) .as-console-wrapper {max-height: 100% !important; top: 0} The second one does add the model/value part at the expense of some additional complexity. And it's not clear to me if it's entirely correct, although I think it's close: const convert = (xs) => Object .fromEntries ( xs .map (({name, type, inputs = [], canHaveMultiple}) => [ name, canHaveMultiple ? {model: convert (inputs), values: [convert (inputs)]} : inputs.length ? convert (inputs) : {type, value: ''} ]) ) const restructure = (context) => ({ data: Object .fromEntries (context .groups .map ( ({heading, inputs, canHaveMultiple}) => [ heading, canHaveMultiple ? {model: convert (inputs), values: [convert (inputs)]} : convert (inputs) ] )) }) const context = {other: "props", groups: [{heading: "basic", canHaveMultiple: !1, inputs: [{name: "username", type: "text", placeholder: "username"}, {name: "password", type: "password", placeholder: "password"}]}, {heading: "about", canHaveMultiple: !1, inputs: [{name: "about", type: "textarea", placeholder: "about", canHaveMultiple: !1}]}, {heading: "hobbies", canHaveMultiple: !0, inputs: [{name: "title", type: "text", placeholder: "about", canHaveMultiple: !1}, {name: "description", type: "description", placeholder: null, canHaveMultiple: !1}]}, {heading: "friends", canHaveMultiple: !0, inputs: [{name: "name", type: "text", placeholder: "this is fine", canHaveMultiple: !1}, {name: "hobbies", type: "nested", canHaveMultiple: !0, inputs: [{name: "title", type: "textarea", placeholder: "about", canHaveMultiple: !1}, {name: "description", type: "textarea", placeholder: "about", canHaveMultiple: !1}]}]}]} console .log (restructure (context)) .as-console-wrapper {max-height: 100% !important; top: 0} In both of them, we could simplify a lot if you had a consistent interface. That is, if groups was called inputs and heading was called name, we could consolidate the two repetitive functions into a single one.
How to remove treeview child node using jquery
I have a treeview like below, i need to remove one child from the list based on the user. Can any one tell me how to remove the child from the treeview. var treedata = [ { label: 'Floor', type: 'Country', children: [ { label: 'Bangalore', type: 'Location', children: [{ label: 'Technopolis', type: 'facility', id: 1 }, { label: 'Ecity Tower-2', type: 'facility', id: 2 }, { label: 'Bagmane', type: 'facility', id: 3 }, { label: 'Cyber Park', type: 'facility', id: 4 }] }, { label: 'Hyderabad', type: 'Location', children: [{ label: 'Hitech City ', type: 'facility', id: 5 }, { label: 'Cyber City', type: 'facility', id: 6 }] }, { label: 'Chennai', type: 'Location', children: [{ label: 'XXX', type: 'facility', id: 7 }] }, { label: 'Mumbai', type: 'facility', id: 8 } ] }, { label: 'Role Administration', type: 'Role', children: [{ label: 'Assign Role', type: 'Role', id: 1 }] }, { label: 'Hoteling Admin', type: 'Hoteling', children: [{ label: 'Hoteling', type: 'Hoteling', id: 1 }] } ]; The above is my jquery tree data. I want to remove the role administration if the user is a normal user by checking the user role. Anyone help me how to do using jquery. Thanks
You can use $.grep() to filter the array to a new array based on whatever conditions you want. var userRole='normal'; if( userRole === 'normal'){ treeview = $.grep(treeview, function(item){ return item.label != 'Role Administration'; }); } grep() API docs
Sencha touch: nested list with multiple root properties
I'm trying to display the JSON structure shown below in a nested list. Each category has a name and consists of subcategories and leafs. { name: 'root', categories: [ { name: 'Category 1', categories: [ { name: 'Category 1.1', leafs: [ { name: 'Leaf 1.1.1', leaf: true }, { name: 'Leaf 1.1.2', leaf: true } ] } ], leafs: [ { name: 'Leaf 1.1', leaf: true }, { name: 'Leaf 1.2', leaf: true } ] }, { name: 'Category 2', leafs: [ { name: 'Leaf 2.1', leaf: true }, { name: 'Leaf 2.2', leaf: true } ] } ] } The data model is the following: Ext.define('MyApp.model.Leaf', { extend: 'Ext.data.Model', config: { fields: [ {name: 'name', type: 'string'} ] } }); Ext.define('MyApp.model.Category', { extend: 'Ext.data.Model', //requires: ['MyApp.model.Leaf'], config: { fields: [ 'id', 'name' ], hasMany: [ { model: 'MyApp.model.Category', name: 'categories', associationKey: 'categories' }, { model: 'MyApp.model.Leaf', name: 'statistics', associationKey: 'leafs' } ], proxy: { type: 'ajax', url : 'http://192.168.178.103?data', reader: { type: 'json', rootProperty: 'categories' } } } }); And here is the nested list: { xtype: 'nestedlist', title: 'Kategorien', displayField: 'name', store: Ext.create('Ext.data.TreeStore', { model: 'MyApp.model.Category' }) } The problem is: The nested list shows me all categories und their child categories correctly, but I'm not able to get the leafs displayed. I think the reason is that the identifier of the leaf array is named 'leafs' and therefor is not recognized but i can only give one root property identifier. Any ideas? Thanks in advance.
Empty rows appear in grid
I'm trying to create a grid (Ext.grid.Panel) and fill it with data. But something is going wrong so the grid shows empty rows without data. Model is: Ext.define('Order', { extend: 'Ext.data.Model', fields: [ { name: 'id', type: 'int' }, { id: 'companyId', type: 'int' }, { id: 'amount', type: 'int' }, { id: 'dealDate', type: 'date' }, { id: 'complete', type: 'int' //boolean imitation } ], idProperty: 'id' }); Grid & Store code is: var orders = Ext.create('Ext.data.Store', { model: 'Order', proxy: Ext.create('Ext.data.proxy.Ajax', { url: 'service/orders-data.php?', reader: Ext.create('Ext.data.reader.Json', { root: 'orders' }) }), sorters: [{ property: 'name', direction: 'ASC' }] }); orders.load(); var ordersGrid = Ext.create('Ext.grid.Panel', { width: 400, height: 300, store: orders, columns: [ { text: 'Amount', dataIndex: 'amount', width: 120 }, { text: 'Deal date', dataIndex: 'dealDate', width: 120 }, { text: 'Complete', dataIndex: 'complete', width: 120 } ] }); JSON-response from server is: { "orders":[ { "id":1, "amount":5000, "dealDate":"2012-01-05", "complete":0 }, { "id":2, "amount":6850, "dealDate":"2012-01-07", "complete":0 }, { "id":5, "amount":7400, "dealDate":"2012-01-09", "complete":0 } ] } Why does the grid display empty rows?
All your model's fields but the first are being declared with 'id' properties where they should instead be using 'name': { name: 'id', type: 'int' }, { name: 'companyId', type: 'int' }, { name: 'amount', type: 'int' }, { name: 'dealDate', type: 'date' }, { name: 'complete', type: 'int' //boolean imitation }