So erstellen Sie eine mehrstufige Dropdown-Liste und binden sie an Daten, die vom Server stammen

15

Ich bin sehr neu in Angular. Ich habe einige Arbeiten an Angular.

Ich muss die verschachtelte Dropdown-Liste für JsonDaten, die vom Server kommen, durch Aufrufen von Rest Api binden .

Daten haben ein Attribut LgLevel: Gibt die Ebene in der Hierarchie der Gruppe an. Elternteil hat level=0, Immediate Child=1, Grandchild=2und so weiter. Childund Grandchildhat ein ParentLocationGroupFeld, das anzeigt, in welchem ​​übergeordneten Menü sich das untergeordnete Menü befindet.

Das sind meine jsonDaten. Ich habe riesige Daten, aber nicht alle.

{
"ArrayOfLocationGroup": {
  "LocationGroup": [
     {
        "Id": "628",
        "Name": "TEST1",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources"
        },
        "ParentLocationGroup": {
           "_uuid": "bdce4396-9c60-4831-90f2-6f793becb362",
           "__text": "570"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "0"
        }
     },
     {
        "Id": "630",
        "Name": "TEST2",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "PAM-TEST"
        },
        "ParentLocationGroup": {
           "_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
           "__text": "628"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "1"
        }
     },
     {
        "Id": "631",
        "Name": "TEST3",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "PAA-TEST"
        },
        "ParentLocationGroup": {
           "_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
           "__text": "628"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "1"
        }
     },
     {
        "Id": "697",
        "Name": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "TEST4"
        },
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "PAE-TEST"
        },
        "ParentLocationGroup": {
           "_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
           "__text": "628"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "1"
        }
     },
     {
        "Id": "700",
        "Name": "TEST5",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "cuba"
        },
        "ParentLocationGroup": {
           "_uuid": "704af4cf-9feb-4f1b-aa00-d1c7926f7901",
           "__text": "694"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "2"
        }
     },
     {
        "Id": "706",
        "Name": "TEST5",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "VOIP-Test"
        },
        "ParentLocationGroup": {
           "_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
           "__text": "628"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "1"
        }
     },
     {
        "Id": "718",
        "Name": "TEST7",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources"
        },
        "ParentLocationGroup": {
           "_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
           "__text": "628"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "1"
        }
     },
     {
        "Id": "719",
        "Name": "TEST8",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "MEM_RS"
        },
        "ParentLocationGroup": {
           "_uuid": "52073e2b-48b5-41a9-9c2b-d793835cf285",
           "__text": "718"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "2"
        }
     },
     {
        "Id": "752",
        "Name": "TEST9",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "ELDIT"
        },
        "ParentLocationGroup": {
           "_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
           "__text": "628"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "1"
        }
     },
     {
        "Id": "753",
        "Name": "TEST10",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "GXYA"
        },
        "ParentLocationGroup": {
           "_uuid": "52073e2b-48b5-41a9-9c2b-d793835cf285",
           "__text": "718"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "2"
        }
     },
     {
        "Id": "760",
        "Name": "TEST11",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "STAGE2"
        },
        "ParentLocationGroup": {
           "_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
           "__text": "628"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "1"
        }
     },
     {
        "Id": "761",
        "Name": "TEST12",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "INIT"
        },
        "ParentLocationGroup": {
           "_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
           "__text": "628"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "1"
        }
     },
     {
        "Id": "762",
        "Name": "TEST13",
        "GroupId": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "USIT"
        },
        "ParentLocationGroup": {
           "_uuid": "894055b6-b132-4dc2-a12a-971ecc0c7224",
           "__text": "628"
        },
        "LgLevel": {
           "_xmlns": "http://www.air-watch.com/servicemodel/resources",
           "__text": "1"
        }
     }
  ],
  "_xmlns:xsd": "http://www.w3.org/2001/XMLSchema"
}
}

Ich habe versucht, es zu entwickeln, aber ich habe alle Beispiele bootstrapmit statischen Daten in einer htmlDatei und einer separaten CSSDatei gefunden, was für mich kompliziert war.

Ich möchte es dynamisch mit verwenden TypeScript. Wie kann ich anfangen daran zu arbeiten?

Arvind Chourasiya
quelle
Erstens ist das Datenformat XMLund nicht JSON. Können Sie auch hinzufügen, was Sie versucht haben? Vielleicht detaillierter der Ansatz, den Sie gewählt haben.
vatz88
@ vatz88 - Ja, das ist XML, das gerade vom Postboten eingefügt wurde. Ich habe htmlCode mit statisch verschachtelten Listen ausprobiert . Ich werde versuchen, es zu bearbeiten und JsonDaten veröffentlichen. Du wirst nicht mögen, was ich versucht habe :)
Arvind Chourasiya
Sie müssen sich keine Sorgen machen, was Sie bisher codiert haben. Der Ansatz wäre - die Daten in der ts-Datei fest zu codieren, im HTML-Code Bindungen gemäß den Daten zu erstellen, die Sie zum Rendern der Dropdown-Liste benötigen. Sobald diese Logik korrekt ist, arbeiten Sie daran, die Daten dynamisch abzurufen, und lassen Sie dann den Winkel mit der Bindung die Magie wirken.
vatz88
@ vatz88 - Mein statischer Code war in der htmlDatei. Ich habe eine Idee, es zu starten. Du kannst mir helfen.
Arvind Chourasiya
@ArvindChourasiya gibt es viele Kinder von LgLevel 1, wie kann man feststellen, welches Enkelkind von LgLevel 2 zu welchem ​​Kind gehört?
Satish Pai

Antworten:

4

Dies ist ein codiertes Beispiel, das Sie gemäß den Daten der verschachtelten Ebene aus Ihren JSON-Daten benötigen. Jetzt können Sie die formatierten JSON-Daten im DOM mithilfe von Modelldaten schleifen . Ich hoffe, dies wird Ihnen dabei helfen, ein mehrstufiges Dropdown-Menü zu erstellen

groupBy(xs, key) {
   return xs.reduce(function (rv, x) {
     (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
   }, {});
 }

var model;

getData() {
 var   sampleData = {
  "ArrayOfLocationGroup": {
    "LocationGroup": [
      ...
      ...//Server response data
      ],
    "_xmlns:xsd": "http://www.w3.org/2001/XMLSchema"
  }
 }    

var list = this.sampleData["ArrayOfLocationGroup"]["LocationGroup"];
var formattedList = [];

list.forEach(element => {

  var obj = {  //Make sure your server response data to like this structure
    "Id": element.Id,
    "Name": element.Name,
    "GroupId": element.GroupId.__text,
    "ParentLocationGroup": element.ParentLocationGroup.__text,
    "LgLevel": element.LgLevel.__text,
    "Child" : []
  }
  formattedList.push(obj);
});

var groupDataList = this.groupBy(formattedList, "LgLevel");

var parents = groupDataList[0];
var child = groupDataList[1];
var childOfChild = groupDataList[2];

child.forEach(c => {
  c.Child = childOfChild.filter(x => x.ParentLocationGroup == c.Id);
})

parents.forEach(p => {
  p.Child = child.filter(x => x.ParentLocationGroup == p.Id);
})

this.model = parents;
}

HTML-Datei

    <ul class="nav site-nav">
     <li class=flyout>
      <a href=#>Dropdown</a>
      <!-- Flyout -->
      <ul class="flyout-content nav stacked">
        <li *ngFor="let parent of model" [class.flyout-alt]="parent.Child.length > 0"><a href=#>{{parent.Name}}</a>
          <ul *ngIf="parent.Child.length > 0" class="flyout-content nav stacked">
            <li *ngFor="let c of parent.Child" [class.flyout-alt]="c.Child.length > 0"><a href=#>{{c.Name}}</a>
              <ul *ngIf="c.Child.length > 0" class="flyout-content nav stacked">
                <li *ngFor="let cc of c.Child" [class.flyout-alt]="cc.Child.length > 0"><a href=#>{{cc.Name}}</a></li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
    </li>
  </ul>

Organisieren Sie die Modelldaten gemäß Ihren Serverantwortdaten. Antwort json Format geändert ( __text zu #text )

 var obj = {
    "Id": element.Id,
    "Name": element.Name && element.Name.#text ? element.Name.#text : element.Name,
    "GroupId": element.GroupId && element.GroupId.#text ? element.GroupId.#text : element.GroupId,
    "ParentLocationGroup": element.ParentLocationGroup && element.ParentLocationGroup.#text ? element.ParentLocationGroup.#text : element.ParentLocationGroup,
    "LgLevel": element.LgLevel && element.LgLevel.#text ? element.LgLevel.#text : element.LgLevel,
    "Child" : []
  }
Yaseer
quelle
Können Sie bitte auch eine HTML-Datei posten?
Arvind Chourasiya
@ArvindChourasiya Müssen Sie Tag Dropdown oder nur Dropdown ( Link ) auswählen ?
Yaseer
Ich muss wie es in dolor Option über den obigen Link angezeigt wird.
Arvind Chourasiya
@ArvindChourasiya Ich habe den Beitrag mit HTML aktualisiert
Yaseer
Ich bin wenig verwirrt mit Ihrem Code. Sie verwenden getDatanirgendwo. Könnten Sie bitte Ihren Code eins überprüfen und Öffnungen und Verschlüsse hinzufügen.
Arvind Chourasiya
4

Anscheinend haben Sie bereits eine andere Antwort, die Ihren Anforderungen entspricht. Aber diese Lösung hat mich einige Zeit gekostet. Also habe ich beschlossen, es trotzdem zu posten.

Das folgende Codeausschnitt wird verwendet, um die baumartige Struktur der hierarchischen Eltern-Kind-Daten zu erstellen:

  processData(data) {
    let locationData = data.ArrayOfLocationGroup.LocationGroup;
    let level0 = [];
    let tempMap = {};
    for (let i = 0; i < locationData.length; i++) {
      let currItem = this.getDataObject(locationData[i]);
      if (tempMap[currItem.id] == undefined) {
        tempMap[currItem.id] = currItem;
        if (tempMap[currItem.parentLocationGroup] == undefined) {
          tempMap[currItem.parentLocationGroup] = { children: [] };
        }
        tempMap[currItem.parentLocationGroup].children.push(currItem);
      } else {
        if (tempMap[currItem.id]) {
          currItem.children = tempMap[currItem.id].children;
        }
        tempMap[currItem.id] = currItem;
        if (tempMap[currItem.parentLocationGroup] == undefined) {
          tempMap[currItem.parentLocationGroup] = { children: [] };
        }
        tempMap[currItem.parentLocationGroup].children.push(currItem);
      }
      if (currItem.lgLevel == "0") {
        if (level0.indexOf(currItem) == -1) {
          level0.push(currItem);
        }
      }
    }
    this.levelData = level0;
  }

Die aggregierten Daten werden als Eingabe an eine dropdownKomponente übergeben, die sie als mehrstufiges Dropdown-Menü darstellt.

Diese Lösung funktioniert angeblich für alle Kinder. Die dropdownKomponente kann geändert werden, um die Art und Weise zu ändern, in der die Daten gemäß Ihren Anforderungen gerendert werden.

Ich habe das htmlund cssfür das mehrstufige Dropdown-Menü von hier genommen:
https://phppot.com/css/multilevel-dropdown-menu-with-pure-css/
Der Code zum Schließen des Menü-Dropdowns, wenn außerhalb dieser Antwort geklickt wird:
https: //stackoverflow.com/a/59234391/9262488

Ich hoffe, Sie finden das nützlich.

NiK648
quelle
Ich habe Ihren Code überprüft. Es funktioniert. Vielen Dank für die Antwort Antwort. Können Sie mir bitte sagen, wie Sie meine Daten erhalten? für http Anfrage (mocky.io).
Arvind Chourasiya
Mocky ist ein Online-Tool zum Erstellen von Mock-Rest-APIs. Ich habe die von Ihnen geposteten Daten verwendet, um mit mocky eine Rest-API zu erstellen.
NiK648
1

Warum nicht eine Baumkomponente erstellen und Eingaben rekursiv daran binden?

Die vorgeschlagene Lösung ist

  • Tiefenunabhängig - Es funktioniert für eine beliebige Anzahl von Ebenen in Ihrem Datenbaum (auch wenn es sich ad-hoc ändert).
  • Sehr effizient - es aggregiert Ihre Daten in O(n).

Entwerfen Sie zuerst das Datenmodell - es muss eine Baumknotenstruktur sein:

export interface GroupId { /* appropriate members... */ }

export interface ParentLocationGroup { /* other members... */ __text: string; }

export interface LgLevel { /* other members... */ __text: string; }

export interface DataModel {
  Id: string,
  Name: string,
  GroupId: GroupId,
  ParentLocationGroup: ParentLocationGroup,
  LgLevel: LgLevel,
  children: DataModel[]
}

Aggregieren Sie dann Ihre Daten in der Komponente der obersten Ebene (oder noch besser - in Ihrem Datendienst; Sie sollten in der Lage sein, dies leicht genug zu abstrahieren):

// dropdown.component.ts

@Component({
  selector: 'app-dropdown',
  template: `
    <ul class="nav site-nav">
      <li class=flyout>
        <a href=#>Dropdown</a>
        <app-dynamic-flyout [data]="data"></app-dynamic-flyout>
      </li>
    </ul>
  `
})
export class DropdownComponent {

  data: DataModel[];

  constructor(dataService: YourDataService){

    let data;
    dataService.getYourData()
      .pipe(map(d => d.ArrayOfLocationGroup.LocationGroup)))
      // Make sure every item has the `children` array property initialized
      // since it does not come with your data
      .subscribe(d => data = d.map(i => ({...i, children: []})));

    // Create a lookup map for building the data tree
    let idMap = data.reduce((acc, curr) => ({...acc, [curr.Id]: curr}), {});
    this.data = data.reduce(
      (acc, curr) => curr.LgLevel.__text == 0 || !curr.ParentLocationGroup
        // Either the level is 0 or there is no parent group
        // (the logic is unclear here - even some of your lvl 0 nodes have a `ParentGroup`)
        // -> we assume this is a top-level node and put it to the accumulator
        ? [...acc, curr]
        // Otherwise push this node to an appropriate `children` array
        // and return the current accumulator
        : idMap[curr.ParentLocationGroup.__text].children.push(curr) && acc, 
      []
    );
  }
}

Und erstellen Sie die wiederkehrende dynamische Flyout-Komponente:

// dynamic-flyout.component.ts

@Component({
  selector: 'app-dynamic-flyout',
  template: `
    <ul *ngIf="!!data.length" class="flyout-content nav stacked">
      <li *ngFor="let item of data" [class.flyout-alt]="!!item.children.length">
        <a href=#>{{item.Name}}</a>
        <app-dynamic-flyout [data]="item.children"></app-dynamic-flyout>
      </li>
    </ul>
  `
})
export class DynamicFlyoutComponent {
  @Input() data: DataModel[];
}

Die Lösung ist nicht getestet, soll aber in die richtige Richtung weisen ...

Hoffe das hilft ein wenig :-)

Heehaaw
quelle