stack s
stack s

Reputation: 119

data manipulation inside nested array

In the below data structure,

data = {
  data: [{
    areas: [{
      sections: [{
          rjf: [{
            type: 'heading-1'
            text: 'Sample Heading',
          }]
        },
        {
          rjf: [{
              type: 'paragraph',
              depth: 0,
              text: 'This website is offered to you by:',
              inlineStyleRanges: [],
              inlineEntityRanges: []
            },
            {
              "type": "ordered-list-item",
              "text": "Ordered Item A",
            },
            {
              "type": "unordered-list-item",
              "text": "Ordered Item B",
            },
            {
              type: 'paragraph',
              depth: 0,
              text: 'This website is offered to you by:',
              inlineStyleRanges: [],
              inlineEntityRanges: []
            },
            {
              "type": "ordered-list-item",
              "text": "Ordered Item A",
            },
            {
              "type": "unordered-list-item",
              "text": "Ordered Item B",
            }
          ]
        }
      ]
    }]
  }]
};

I'm trying to group all the type which as ordered-list-item & unordered-list-item into new object. Something like below,

{
    "type": 'list',
    "items": [
      {
        "type": "ordered-list-item",
        "text": "Ordered Item A",
      },
      {
        "type": "unordered-list-item",
        "text": "Ordered Item B",
      }
    ]
  }

After so much treble, I came with the below solution. This works fine. But having an issue, In rjf if ordered-list-item & unordered-list-item not found nothing should be happen unfortunately and empty list getting added to rjf.

Below is the code snippet, please help me to fix this issue.

const data = {
  data: [{
    areas: [{
      sections: [{
          rjf: [{
            text: 'Sample Heading',
          }]
        },
        {
          rjf: [{
              type: 'paragraph',
              depth: 0,
              text: 'This website is offered to you by:',
              inlineStyleRanges: [],
              inlineEntityRanges: []
            },
            {
              "type": "ordered-list-item",
              "text": "Ordered Item A",
            },
            {
              "type": "unordered-list-item",
              "text": "Ordered Item B",
            },
            {
              type: 'paragraph',
              depth: 0,
              text: 'This website is offered to you by:',
              inlineStyleRanges: [],
              inlineEntityRanges: []
            },
            {
              "type": "ordered-list-item",
              "text": "Ordered Item A",
            },
            {
              "type": "unordered-list-item",
              "text": "Ordered Item B",
            }
          ]
        }
      ]
    }]
  }]
};
const moveToNewObject = (data) => {
  const sections = data[0].areas[0].sections;
  sections.forEach(data => {
    let list = data.rjf;
    let a = list.map((entry, index) => {
      return { ...entry,
        index,
        use: entry.type !== 'unordered-list-item' && entry.type !== 'ordered-list-item'
      }
    }).filter(entry => entry.use).map((entry, index, entries) => {
      const end = index < entries.length - 1 ? entries[index + 1].index : list.length - entry.index;
      return [{
        type: entry.type,
        text: entry.text
      }, {
        type: 'list',
        items: list.slice(entry.index + 1, entry.index + end)
      }]
    });
    console.log(a);
  });
}
console.log(moveToNewObject(data.data));

Upvotes: 0

Views: 103

Answers (2)

dziraf
dziraf

Reputation: 3653

Your data has a very weird structure which makes it harder to be honest. The snippet below uses a function that uses map on all your sections, and if rjf type is 'unordered-list-item' or 'ordered-list-item', it moves it to a new rjf of type list as items. Hopefully it's what you wanted.

And here's a fiddle if you want clearer code formatting: https://jsfiddle.net/qce2vLr3/

const data = {
  data: [
    {
      areas: [
        {
          sections: [
            {
              rjf: [
                {
                  text: 'Sample Heading',
                }
              ]
            },
            {
              rjf: [
                {
                  type: 'paragraph',
                  depth: 0,
                  text: 'This website is offered to you by:',
                  inlineStyleRanges: [],
                  inlineEntityRanges: []
                },
                {
                  "type": "ordered-list-item",
                  "text": "Ordered Item A",
                },
                {
                  "type": "unordered-list-item",
                  "text": "Ordered Item B",
                }
              ]
            }
          ]
        }
      ]
    }
  ]
};

const moveToNewObject = (data) => {
	const sections = data[0].areas[0].sections; // why is data an array?
  return sections.map((section) => {
  	if (section.rjf) {
    	const looseItems = section.rjf.filter((rjf) => rjf.type && ['ordered-list-item', 'unordered-list-item'].includes(rjf.type));
      if (looseItems.length) {
      	return { 
        	rjf: [
          	...section.rjf,
          	{ 
          		type: 'list',
            	items: looseItems 
          	}
          ].filter((rjf) => rjf.type && !['ordered-list-item', 'unordered-list-item'].includes(rjf.type))
        }
      }
      return section;
    }
    return section;
  })
}

data.data[0].areas[0].sections = moveToNewObject(data.data);
console.log(data.data);

UPDATE

Here's a solution that "groups" your lists by multiple headings: https://jsfiddle.net/pkLyd0gh/

const data = {
  data: [
    {
      areas: [
        {
          sections: [
            {
              rjf: [
                {
                  text: 'Sample Heading',
                }
              ]
            },
            {
              rjf: [
                {
                  "type": "heading-1",
                  "text": "A title",
                },
                {
                  "type": "ordered-list-item",
                  "text": "Ordered Item A",
                },
                {
                  "type": "unordered-list-item",
                  "text": "Ordered Item B",
                },
                {
                  "type": "heading-2",
                  "text": "A title",
                },
                {
                  "type": "ordered-list-item",
                  "text": "Ordered Item C",
                },
                {
                  "type": "unordered-list-item",
                  "text": "Ordered Item D",
                }
              ]
            }
          ]
        }
      ]
    }
  ]
};

const reformattedSections = (data) => {
	const sections = data[0].areas[0].sections;
  const listItemTypes = ['unordered-list-item', 'ordered-list-item'];
  return sections.map((section) => {
  	let lastHeadingIndex = -1;
  	return section.rjf.reduce((acc, current, index) => {
    	if (!current.type || !listItemTypes.includes(current.type)) {
      	lastHeadingIndex = acc.length;
        return [...acc, current]
      }
      else {
      	let listObject = acc.find((el, i) => i > lastHeadingIndex && i < index && el.type === 'list');
        if (!listObject) {
        	listObject = {
          	type: 'list',
            items: [current]
          }
          return [...acc, listObject];
        }
        listObject.items = [...listObject.items, current];
      	return acc;
      }
    }, [])
  })
}

data.data[0].areas[0].sections = reformattedSections(data.data);
console.log('sections', data.data);

Upvotes: 1

Edwin
Edwin

Reputation: 440

slice is a method on array's not on objects. DATA in your code is an Object

const a ={a:1,b:2,c:3,d:4}
const b =[1,2,3,4]

//console.log(a.slice(1,3)) //this will return the error    
console.log(b.slice(1,3))

Hope it helps.

Upvotes: 0

Related Questions