'How to map a subarray

I am using a sample I found online to map a subarray and can't seem to get it to work.

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-map-subarray',
  templateUrl: './map-subarray.component.html',
  styleUrls: ['./map-subarray.component.css']
})
export class MapSubarrayComponent implements OnInit {

  books: any[] = [
    {
      title: 'Books by Nigerian authors',
      // An array of books in shelves
      shelves: [
        {
          id: 1,
          category: 'Fiction',
          title: 'Things fall Apart',
          author: 'Chinua Achebe'
        },
        {
          id: 2,
          category: 'drama',
          title: 'Under the Udala trees',
          author: 'Chinelo Okparanta'
        }
      ]
    }
  ];
  categories: any[] = [];

  constructor() { }

  ngOnInit(): void {
    // Gets the selves from the books array
    this.categories = this.books.map((book) => this.books.shelves);
    
    // Gets the list of categories on the shelves
    this.categories = this.books.map((book) => book.shelves.map((shelf) => shelf.category);
  }

}

But I get an error in the first map on shelves:

enter image description here

And an error on shelf for the second mapping line. Perhaps fixing the 1st map will lead to fixing the second.

enter image description here

jitendra's answer works fine.

But I am curious why using the map for shelves gives me back an array which I cannot apparently use - ie. shelves.title. And it doesn't work in the template with the *ngFor.

But the index one does work.

Does that have something to do with flattening?

enter image description here

enter image description here



Solution 1:[1]

To get shelves you didn't require use map function.

You can use the below code to get shelves. as you can see in the first index of the array you have shelves. so you need to 0th index to get shelves.

this.categories = [...this.books[0].shelves];

Or using if you want to use map then you can use this code:

this.categories = this.books.map((book) => this.books[0].shelves);

// Gets the list of categories on the shelves

I think you missed one round bracket. You can try this code:

this.categories = this.books.map((book) => book.shelves.map((shelf) => shelf.category));
 // this.categories It will console ["Fiction","drama"]
 console.log(this.categories);

Solution 2:[2]

It's always a good idea to type your objects in Angular, which uses TypeScript - in your case, since your books aren't types, the compiler gives it an any type if it can't infer the types. If you have strict mode turned on, you will see errors.

If you were to type your book, you may have something like:

// You can use a Class or Type if you prefer
interface Book{
    title: string,
    shelves: {
          id: number,
          category: string,
          title: string,
          author: string
        }[]
}

This way, even using the Array.map method, you should not see the "implicit any" warning

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 marc_s
Solution 2 Laurence Ininda