0

My objectif is to display the elements of a given array of components in a number of columns that changes dynamically.

Example: Let's say that we have the following array:

[a, b, c, d, e, f, g, h]

If the number of columns is 3, the display of this array's elements would be:

a b c 
d e f
g h

Otherwise, if the number of columns is 5, the display would be:

a b c d e
f g h

Implementation:

I implemented a solution that serves my purpose in this Plunker (the number of columns is stored in the variable columnsNumber), but it's pure algorithmic and I am wondering if there would be better solutions.

Usages:

This solution can be used for example to construct dynamic forms, where each column contains a form's control or component.

1 Answer 1

1

The main problem with the approach that you're using in the plunker is that the function "initArrayOfNumbers" is being called on every ChangeDetection.

To solve your problem I'd recommend you to use SlicePipe, like this:

<div *ngFor="let i of rows">
  <span *ngFor="let col of columns | slice: (i * columnSize): (i + 1) * columnSize">
    {{ col.name }}
  </span>
</div>

Where rows is defined here:

this.rows = Array.from({ length: Math.ceil(this.columns.length / this.columnSize) }, (v, k) => k);

Explanation:

It's a simple array containing a generated sequence, ie: if columnSize is 3 and your array is between (inclusive) 6 and 9 (inclusive) rows will be [0, 1, 2], so you can use it to make calculations on SlicePipe.

You can check this simple DEMO to see it working.


If you're looking for a more generic solution, you could create a custom pipe:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'chunk'
})
export class ChunkPipe implements PipeTransform {

  transform(input: any, size: number): any {

    if (!Array.isArray(input) || !size) {
      return [];
    }

    const intSize: number = parseInt(size, 10);
    return Array.from({ length: Math.ceil(input.length / intSize) }, (v, k) => input.slice(k * intSize, k * intSize + intSize));
  }
}

Template:

<div *ngFor="let col of columns | chunk: columnSize">
  <span *ngFor="let item of col">
    {{ item.name }}
  </span>
</div>

Also, don't forget to add the pipe to your declarations in NgModule:

@NgModule({
  ...
  declarations: [
    // Other declarations
    ChunkPipe
  ],
  ...
})

DEMO

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

1 Comment

A nice and smart solution, the custom pipe is very handy

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.