0

I have this array of objects and I want to get all the controls from this to another array:

this.formModel = {
    sections: [
        {
            title: 'Section 01',
            controls: [
                new FormControlInput({
                    key: 'name 01',
                    label: 'Name 01'
                }),
                new FormControlSelect({
                    key: 'abc',
                    label: 'Abc'
                })
            ]
        },
        {
            title: 'Section 02',
            controls: [
                new FormControlInput({
                    key: 'name 02',
                    label: 'Name 02'
                })
            ]
        }
    ]
};

I am using map for this but I am not getting single array, I am getting array of arrays:

this.formModel.sections.map(function (x) { return x.controls; })

Getting this:

[
     {
        [{
            key: 'name 01',
            label: 'Name 01'
        },
        {
            key: 'abc',
            label: 'Abc'
        }]
     },
     {
        [{
            key: 'name 02',
            label: 'Name 02'
        }]
     }
]

What I want is this:

[
    {
        key: 'name 01',
        label: 'Name 01'
    },
    {
        key: 'abc',
        label: 'Abc'
    },
    {
        key: 'name 02',
        label: 'Name 02'
    }       
]
6
  • please add FormControlInput as well. Commented Sep 6, 2017 at 8:45
  • What does FormControlInput return? Commented Sep 6, 2017 at 8:48
  • Obviously, FormControlInput just return an object. Commented Sep 6, 2017 at 8:49
  • Yes simple TypeScript class. Commented Sep 6, 2017 at 8:50
  • @Cerbrus I commented when it wasn't clear. Commented Sep 6, 2017 at 8:50

3 Answers 3

2

You just need to flatten your array after mapping:

var obj = {
  sections: [{
      title: 'Section 01',
      controls: [
        { key: 'name 01', label: 'Name 01' },
        { key: 'abc', label: 'Abc' }
      ]
    }, {
      title: 'Section 02',
      controls: [
        { key: 'name 02', label: 'Name 02' }
      ]
    }
  ]
};

var mapped = obj.sections.map(function (x) { return x.controls; });
var flattened = [].concat.apply([], mapped);
console.log(flattened);

To simplify your example:

// This is your structure:
var sections= [{
      controls: [{}, {}] // C1
    }, {
      controls: [{}]     // C2
    }
];

// With the map, grabbing each `controls` property, and using that as an entry in your array:
var mapped = sections.map(function (x) { return x.controls; });
console.log(mapped);
// [[{},{}],[{}]]
//  ^ C1    ^ C2

// We need to remove that extra layer of arrays:
var flattened = [].concat.apply([], mapped);
console.log(flattened);

Sign up to request clarification or add additional context in comments.

5 Comments

But why this is happening?
controls is an array of objects. I've added a simplified example. I hope this makes it a little easier to visualize what's happening.
I think what's missing is an explanation of Array.prototype.apply, and how it takes arguments as an array. So in the end, the call becomes something similar to spreading the mapped array, like so: var flattened = Array.prototype.concat([], ...mapped).
@jonahe: I'm pretty sure the "Why is this happening" is referring the the nested arrays.
Ah, maybe.. But then wouldn't this question have been.. in the question, instead of in this comment? (And in no other comments to any other answers). Either way, ff .map is unclear to OP, then I guess [].concat.apply([], mapped) wouldn't be obvious either.
1

You can use reduce to flatten the hierarchy

formModel.sections
  .map(x =>  x.controls)
  .reduce((prev, current) => prev.concat(current), [])

Comments

1

Use reduce instead of map:

let formModel = {
    sections: [
        {
            title: 'Section 01',
            controls: [
                {
                    key: 'name 01',
                    label: 'Name 01'
                },
                {
                    key: 'abc',
                    label: 'Abc'
                }
            ]
        },
        {
            title: 'Section 02',
            controls: [
                {
                    key: 'name 02',
                    label: 'Name 02'
                }
            ]
        }
    ]
};

let result = formModel.sections.reduce((res, section) => {
	return res = res.concat(section.controls); 
}, []);

console.log(result);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.