0

I have an array of arrays that I want to use as a directory. The point is to sort all the items according to which letter they begin with.

Here is the code of my item list component :

let itemList = ["Plane","Bird","Boat"];
let directory = [];
for (const item of this.itemList) {
    if (this.directory[item.charAt(0).toLowerCase()] == null || undefined) {
        this.directory[item.charAt(0).toLowerCase()] = [];
    }
    this.directory[item.charAt(0).toLowerCase()].push(item);
}

Then I want to display all my items sorted according to their first letter, and I want that first letter to be displayed above the list of items that begin with it, just like a directory. I use the following template in HTML :

<div id="item-list">
  <div *ngFor="let entry of directory ; let i = index">
    <p>{{i}}</p>
    <div *ngFor="let item of entry">
      <p>{{item}}</p>
      <app-item></app-item>
    </div>
  </div>
</div>

However, when I run my app, I see no data displayed in HTML. I tried to print text at several points :

<div id="item-list">
  <p>Hello</p>
  <div *ngFor="let entry of directory ; let i = index">
    <p>Hello again</p>
    <p>{{i}}</p>
    <div *ngFor="let item of entry">
      <p>{{item}}</p>
      <app-item></app-item>
    </div>
  </div>
</div>

The webpage displays"Hello", but no "Hello again" (while I think the latter should be printed twice). However, there is absolutely no error message neither when running ng serve nor loading the page. I've searched on the web for a similar problem, but nobody seems to be facing the same difficulties to dynamically display an array of arrays.

Can you tell me what I am doing wrong? Any help would be greatly appreciated. :)

2
  • put a (non-correct but) working example on stackblitz pls. Commented Nov 3, 2018 at 1:18
  • Sure! Here you go: angular-s2nlsn.stackblitz.io Commented Nov 3, 2018 at 1:37

4 Answers 4

1

stackblitz: https://stackblitz.com/edit/angular-tujusv

The directory array is a key:value pair array. You can store the keys in a different array and access them in the html

export class ItemListComponent implements OnInit {
  alphabet: string[];
  directory = [];
  dirArr =[];
  itemList = ["Plane", "Bird", "Boat"];
  constructor() {
    this.alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"];

  }


  ngOnInit() {

    this.itemList.sort();
    for (const item of this.itemList) {
      if (this.directory[item.charAt(0).toLowerCase()] == null || undefined) {
        this.directory[item.charAt(0).toLowerCase()] = [];
      }
      this.directory[item.charAt(0).toLowerCase()].push(item);
      console.log(this.directory);
      this.dirArr = Object.keys(this.directory);
      console.log(this.dirArr)

    }

    console.log(this.directory['p']);


  }
}

HTML:

<div id="item-list">
  <p>Hello</p>
  <div *ngFor="let entry of dirArr ; let i = index">
    <p>Hello again</p>
    <p>{{i}}</p>
    <p>{{entry}}</p>
    <p>{{directory[entry]}}</p>
    <div *ngFor="let item of directory[entry]">
      <p>{{item}}</p>
    </div>
  </div>
</div>
Sign up to request clarification or add additional context in comments.

1 Comment

Worked perfectly! I was trying to figure out something like Object.keys(), but I had only tried in the template. Thank you for your help.
1

make one temp variable and your other code is fine: only change below code:

let itemList = ["Plane","Bird","Boat"];
  let temp = {};
  let directory = []

 for (const item of this.itemList) {

    if (this.temp[item.charAt(0).toLowerCase()] == null || undefined) {
        this.temp[item.charAt(0).toLowerCase()] = [];
    }
    this.temp[item.charAt(0).toLowerCase()].push(item);

  }
   this.directory = Object.values(this.temp)

3 Comments

Thank you for answer. It allows my array of objects to be displayed, which is what I was asking for in the question. However, I did not manage to display the begining letter above the words using your code. It seems to me that it only allows to display the values, not the letter keys, while I needed both. That is why I accepted @zer0' answer instead, but then again, thank you very much for your answer.
Sorry I misunderstood your question I will update this answer accordingly
0

Keyed and nested structures in JavaScript are constructed using OLN. They support for key:value pairs in the way you are attempting to structure your data.

Your use case data structure seems to be:

{
  b : ["Bird", "Boat"],
  p  : ["Plane"]
}

But you are attempting to construct:

[
  b => [ "Bird", "Boat"], p => ["Plane"]
]

Which is not valid in JavaScript.

Change your declaration of directory from [] to {}

3 Comments

Thank you for your answer. I had began using directory as an object, but then I had the following error thrown in the console : Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays. So I thought it was not right to "iterate" on an object with *ngFor and changed to an array. But maybe I was misunderstanding the error.
By the way, what is OLN?
OLN = Object Literal Notation; a javascript object assigned to a variable through object notation {}
0

I've done the below changes to accomplish your requirement try it once.

this.items = this.items.sort();
let currentLetter = this.items[0].charAt(0);
let currentLetterLib = [];
for (let item of this.items) {
  if (item.charAt(0).toLowerCase() != currentLetter) {
      this.directory.push({
        "letter": currentLetter,
        "words": currentLetterLib
      });
      currentLetter = item.charAt(0).toLowerCase();
      currentLetterLib = [];
  }
  currentLetterLib.push(item);
}
this.directory.push({
  "letter": currentLetter,
  "words": currentLetterLib
});

<div id="item-list">
  <p>Hello</p>
  <div *ngFor="let entry of directory ;">
    <p>{{entry.letter}}</p>
    <div *ngFor="let item of entry.words">
      <p>{{item}}</p>
    </div>
  </div>
</div>

1 Comment

Thank you. I did try to use this solution, but it happen to overly complexify the arrays for my purpose, so I sticked to zer0's answer. But thank you very much for your time, I might retry later if have time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.