我有一个类似于此的嵌套 JavaScript 对象 const obj = { topLevelProp1: 'some', topLevelProp2: 'data', topLevelPropArr: [{ uid: 'd7ed3623-e431-4bfa-85b3-8da14fa399c3', secLeve...
我有一个类似于此的嵌套 JavaScript 对象
const obj = {
topLevelProp1: 'some',
topLevelProp2: 'data',
topLevelPropArr: [{
uid: 'd7ed3623-e431-4bfa-85b3-8da14fa399c3',
secLevelProp1: 123,
secLevelPropArr: [{
uid: '15562309-22b7-4b11-a12e-b3374f0a7636',
thirdLevelProp1: 'a plain value',
thirdLevelProp2: {
a: 'I am',
b: 'a nested',
c: 'object',
},
}, {
uid: '9394f313-b7bf-45fa-b8f3-683832ff7aa2',
thirdLevelProp1: null,
thirdLevelProp2: {
a: 'I am also',
b: 'another nested',
c: 'object !!!',
},
}],
}, {
uid: '04a487c6-9624-4b2e-8411-59a69c14f1e3',
secLevelProp1: 456,
secLevelPropArr: [{
uid: '58d4a3fd-734c-4c22-a0e3-f669e6ec7af3',
thirdLevelProp1: 'another plain value',
}],
}],
};
对于任何给定的 嵌套 uid 属性值 都是 (它们是 uuid v4 字符串)
我还有一个字符串数组,描述 某个嵌套属性的路径 ,如下所示:
const paths = [
'topLevelProp2',
'04a487c6-9624-4b2e-8411-59a69c14f1e3.secLevelProp1',
'd7ed3623-e431-4bfa-85b3-8da14fa399c3.9394f313-b7bf-45fa-b8f3-683832ff7aa2.thirdLevelProp2.a',
'd7ed3623-e431-4bfa-85b3-8da14fa399c3.9394f313-b7bf-45fa-b8f3-683832ff7aa2.thirdLevelProp2.c',
];
不使用数组属性的键,而是使用所包含对象的 uid 值
因此该字符串 'd7ed3623-e431-4bfa-85b3-8da14fa399c3.9394f313-b7bf-45fa-b8f3-683832ff7aa2.thirdLevelProp2.a'
以更常见的 'topLevelPropArr.0.secLevelPropArr.1.thirdLevelProp2.a'
对象路径 表示法来表示路径 。
我想以某种方式过滤我的对象,因此它将 仅包含路径数组中包含的(所有嵌套)属性 .
使用上面的例子, 通过
路径 obj
将导致:
{
topLevelProp2: 'data',
topLevelPropArr: [{
secLevelProp1: 456,
secLevelPropArr: [{
thirdLevelProp2: {
a: 'I am also',
c: 'object !!!',
},
}],
}, {
secLevelProp1: 456,
}],
}
没有必要保持数组中项目的顺序。
这是我尝试过的代码(老实说,我认为递归不正确)
const SEPARATOR = '.';
const filterDataByPath = (originalData, path, filteredData = {}) => {
const pathChunks = path.split(SEPARATOR);
const currentChunk = pathChunks[0];
// test whether there is a key in the current level of editData corresponding to the current chunk
if (originalData.hasOwnProperty(currentChunk)) {
// test whether the current value of the current valid key is an object
if (typeof originalData[currentChunk] === 'object') {
// recursively filter this object
filteredData[currentChunk] = filterDataByPath(originalData[currentChunk], pathChunks.splice(1).join(SEPARATOR));
} else {
// take over the data value for the current key
filteredData[currentChunk] = originalData[currentChunk];
}
} else { // find an array containing object with uid
// and ist related key
const [ key, val ] = Object.entries(originalData).reduce((keyArr, [ k, v ]) => {
if (Array.isArray(v)) {
// find the object with matching uid
const targetrArray = v.find(obj => obj.uid === currentChunk);
// if such object found returns it together with the key of the array storing it
if (targetrArray) {
return [ k, targetrArray ];
}
}
return keyArr;
}, []);
// we found such an array
if (key) {
// create a new array in the filtered data under this particular key if not already present
filteredData[key] = Array.isArray(filteredData[key]) ? filteredData[key] : [];
filteredData[key].push(this.filterDataByPath(val, pathChunks.splice(1).join(SEPARATOR)));
} else {
// key not found - throw an exception, something is wrong with our path
throw new Error(`Path not right, unknown chunk ${currentChunk}`);
}
}
return filteredData;
}
let filteredData = {};
for (let index = 0; index < paths.length; index++) {
filteredData = filterDataByPath(originalData, paths[index], filteredData)
};
问题是,过滤数据中的数组有重复的条目
背景:
数据绑定到 Angular 模板驱动表单。由于 no support for FormArrayGroups
in the Template-Driven Forms 可能的解决方法是声明一个 FormGroup
,并为一个分配一个唯一键 ngModelGroup
<fieldset *ngFor="let secLevelItem of data.topLevelPropArr;"
[ngModelGroup]="secLevelItem.uid">
当然,您可以 use index provided by the *ngFor
,但当您按需添加/删除表单字段时,这不起作用。因此,解决方案是 uid
.
这些路径是表单控件名称的连接,提供到特定 dirty
值的路径——在表单中更改的值