• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Angular 7 - Dynamisches Erstellen vom Button und Grids

Tabula_Rasa

Mitglied
Hallo,

ich bin mir nicht sicher, wie ich Folgendes realisieren soll:

Die API liefert beispielweise folgendes Array, in dem Objekte sind (JSON-Format):

Code:
[
{ "id": 2, "bezeichnung": "button1", "zeilen": 30, "spalten": 30, "position": 0, "farbe": "rot", "grid": 
[
 {"zeile":12, "spalte": 5, 
"bezeichnung": "inhalt125" 
},
{
"zeile": 3, "spalte":3, "bezeichnung":"inhalt33"
}
]

Mit den Daten soll ich ein Grid aufbauen, dass die vorgegeben Buttons automatisch generiert mit ihrer Bezeichnung und nach Position (0 - in der Reihe der erste Button) ordnet.

Jeder Button führt zu einem underschiedlichen Grid und Inhalte.

Im "grid" Array sind die jeweiligen Zellen, die an bestimmten Positionen des Grids mit ihren Inhalten zu füllen sind.

Im Prinzip dynamisches Erstellen eines Grid.

Meine Frage: Wie soll ich dieses Konzept realisieren? Mit einem Component und einer Schleife, die einmal alles durchgeht (da sind sehr viele solcher Objekte im Array), oder mehrerer Components?

Ich wüsste auch nicht, wie ich die Schleife aufbauen soll..
Hat jemand einen Vorschlag?
 
Werbung:
Also pro Button ein Grid mit 30 x 30 = 900 Feldern. Wieviele Buttons gibt es denn, und sollen mehrere Grids gleichzeitig auf einer Seite gerendert werden? Das wäre ja ein übler Performance-Killer.

Verlinke doch mal ein reales JSON.

/edit: Button und Grid werden neben- / untereinander angeordnet, oder erzeugt / verlinkt der Button zum Grid?
 
Leider habe ich kein JSON und das war ein schlechtes Beispiel mit der Anzahl an Reihen und Spalten, aber wie du es sagtest, soll es gemacht werden.

Genau dasselbe dachte ich mir auch, dass die Performance echt darunter leidet...

Die Buttons sind frei erstellbar, aber es wird nicht mehr als 10 geben und 4 sind fest - bislang ist es so geplant.

Ob die Grids alle gleichzeitig gerendert werden oder je nach Button-Klick muss noch besprochen werden, aber denke, dass das Rendern aller Grids mit einem Api-Call echt viel wäre.

Der Durchschnitt an Feldern beträgt ca. 40 (5*8), es gibt aber auch Ausnahmen.

Wie wäre die beste Vorgehensweise?

EDIT: Button werden nebeneinander erzeugt, je nach dem welchen Button man klickt, wird das jeweilige Grid erzeugt, die Buttons sind sozusagen die Navigation, also sollte eigentlich verlinkt werden aber einige sind der Meinung, dass ein Component allein ausreicht und in diesem alles gemacht werden soll.
Also ich weiß wirklich nicht wie ich da rangehen soll
 
Zuletzt bearbeitet:
Werbung:
2 Komponenten. Im Parent der Button und die eingebundene Child-Komponente, welche Zeilen, Spalten, Farbe und das grid: [] durchgereicht bekommt. In der Child-Komponente mit diesen Infos ein Grid-Array erstellen, den Inhalt der zu belegenden Felder an die entsprechenden Stellen setzen und das Array anschließend im Child-Template rendern.
 
2 Komponenten. Im Parent der Button und die eingebundene Child-Komponente, welche Zeilen, Spalten, Farbe und das grid: [] durchgereicht bekommt. In der Child-Komponente mit diesen Infos ein Grid-Array erstellen, den Inhalt der zu belegenden Felder an die entsprechenden Stellen setzen und das Array anschließend im Child-Template rendern.

So hatte ich das auch, nur, dass ich fest die Button einprogrammiert habe und dementsprechend mehr als nur ein 2 Components hatte. Ich versuche es mal mit den 2 Components da nur so das dynamische Erzeugen von Buttons realisierbar ist. Danke!
 
Hallo erneut,
ich hätte da noch eine Frage. Das Generieren der Button funktioniert einwandfrei. Jedoch weiß ich nicht genau, wie ich durch das Array loope.
Ich habe eine Klasse erstellt mit einem Adapter, um ein Objekt zu initialisieren (nach dem folgendem Beispiel: https://blog.florimond.dev/consuming-apis-in-angular-the-model-adapter-pattern). Angepasst an das obige JSON sieht sie so aus:

Code:
//adapter.ts
export interface Adapter<T>{
adapt(item: any): T;

//Grid.model.ts
import { Injectable } from '@angular/core';
import { Adapter } from './adapter';

export class Grid {

constructer(
 public id: number,
 public bezeichnung: string,
 public position: number
 public grid: ; // wie ist die Syntax hier und wie                                 //iteriere ich durch das Array
   ){}

}

@Injectable({
    providedIn: 'root'
})
export class GridAdapter implements Adapter<Grid> {

  adapt(item: any): Grid {
    return new Grid(
        item.id,
        item.bezeichnung,
        item.position,
        item.grid,
      );
  }
}

//grid.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Grid, GridAdapter } from './grid.model';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class GridService {

  private baseUrl = 'http://api.myapp.com/grid';

  constructor(
    private http: HttpClient,
    private adapter: GridAdapter,
  ) { }

onGetGrid(): Observable<Grid[]> {
    return this.http.get(this.baseUrl).pipe(
      map((data: any[]) => data.map(item => this.adapter.adapt(item))),
    );
  }
}

Habe da einiges probiert, jedoch scheint wahrscheinlich die Syntax falsch zu sein. Wie müsste das aussehen im grid.model.ts?
 
Werbung:
Hier ist ein Beispiel mit lokalem JSON.


Dieses Adapter-Pattern kenne ich nicht. Wenn ich einen Http Request sende und das Ergebnis in einer Observable speichere, verwende ich ein BehaviourSubject.
 
Ich danke dir. Ich habe da eine Idee und deinen Code zu sehen hilft mir persönlich weiter - ich lerne stets neues, z.B. was BehaviourSubject angeht und inwiefern es sich von Observable unterscheidet.

Auf jeden Fall tut es gut mal anderen Code zu sehen und damit auch neue Möglichkeiten etwas zu implementieren.
Ich versuche mal einen Teil deines Codes zu adaptieren bzw. damit etwas zu experimentieren und bin gespannt, was so dabei herauskommt :).
 
Hier ist ein Beispiel mit lokalem JSON.


Dieses Adapter-Pattern kenne ich nicht. Wenn ich einen Http Request sende und das Ergebnis in einer Observable speichere, verwende ich ein BehaviourSubject.

Ich hätte da noch eine Frage:
Wenn man im Grid-Service kein lokales JSON mehr hätte wie hier:
sondern ein Api-Call

Code:
//grid.service.ts
    getAllOrder(): Observable<Order[]> {
    return this.http.get<Order[]>(this._ordertabanalyseURL + "/" + this.userD + "/" + this.currentUservalueToken);
    };

das liefert ein Observable zurück, kein Array. Ich weiß nicht, wie man das Observable "unwrapped" sodass nur das Order[] Array übrig bleibt und dann via spread-operator ein neues Array füllen kann (siehe Link)

Code:
//grid.service.ts
    get orders(): Order[] {
        return [...this._orderTabs];
    }

Es erscheint stets der Fehler "Cannot read property "map" of undefined im grid.component.ts...
Da ist noch ein dickes Fragezeichen und komme nicht auf die Lösung. Der Api-Call liefert genau das Array aus JSON, so wie das Lokale Array aufgebaut ist.
 
Zuletzt bearbeitet von einem Moderator:
Werbung:
Die Funktion getAllOrder() returned eine Observable, auf die du subscriben musst, um an ihren Inhalt zu gelangen. Dieselbe Prozedur wie in Angular 2.

Der zusätzliche Getter im Service wäre nur dann sinnvoll, wenn du bereits getAllOrder() aufgeführt hättest und aus einer anderen Komponente auf das Ergebnis zugreifen willst, ohne einen weiteren HTTP-Request zu senden. Syntaktisch würde das etwa so aussehen (ungetestet):
Javascript:
private _orders = new BehaviorSubject<any[]>([]);

get orders(): Observable<any[]> {
    return this._orders.asObservable();
}

fetchOrders(): Observable<any[]> {
    return this.http.get<any>(myUrl)
    .pipe(
        take(1),
        tap(orders => this._orders.next(orders))
    );
}
 
Hallo erneut :),

ich habe soweit alles, aber ich weiß nicht wie ich einen bestimmten Wert zur Abfrage accessen kann. Wenn im Grid.model.ts eine Zeile mit der kID hinzufüge und sie folgendermaßen im Code einbinde:

Code:
// grid.component.ts
     this.grid.map((line) => {
       matrix[line.zeile - 1][line.spalte - 1] = [line.bezeichnung, line.kID];
     });

Wie kann ich im HTML-Code eine If-Abfrage starten die nur die kID betrifft, welche nicht angezeigt werden soll?
Wenn die kID == 0 dann Input anzeigen. Wenn kID==1, dann nicht anzeigen.

EDIT: Hab's herausgefunden
 
Zuletzt bearbeitet:
Eine Frage hätte ich noch:

Wie könnte ich lokal am besten die Werte der Check-Box speichern, sodass beim Seitenwechsel die geklickte Checkbox auch noch geklickt bleibt und nicht den Status auf false ändert?

Wie würdest du dan rangehen?
 
Werbung:
In einer Observable.

Wie kann ich das für jede einzelne Zelle auf den verschiedenen "Seiten" speichern? Im Prinzip ist die Vorlage jeder Seite eine einzige Component, nur die Daten unterscheiden sich. Also nehme ich die geklickte Checkbox mit und genau an der n-ten Stelle der anderen Seite ist die Zelle auch geklickt (Checkbox-Wert=true)...
 
Ich bin da jetzt gedanklich nicht so drin. Aber wenn ich vom. Eingangsbeispiel ausgehe, gab es ein Datenobjekt, mit dem ein Grid erzeugt wird. Warum speicherst du den Zustand der Checkbox nicht dort? Mittels 2-Way-Databinding beim Klick.
 
Werbung:
Ich bin da jetzt gedanklich nicht so drin. Aber wenn ich vom. Eingangsbeispiel ausgehe, gab es ein Datenobjekt, mit dem ein Grid erzeugt wird. Warum speicherst du den Zustand der Checkbox nicht dort? Mittels 2-Way-Databinding beim Klick.

Das war mein erster Gedanke, aber beim Wechseln auf eine Seite und wieder zurück, erhalten sie wieder den Wert false, sie sollten aber true bleiben.
Edit: Ich versuche ein kleines Projekt zu erstellen, das mein Problem visuell darstellt.
 
Zurück
Oben