วิธีสร้างรายการแบบหล่นลงหลายระดับและผูกกับข้อมูลที่มาจากเซิร์ฟเวอร์


15

ฉันใหม่กับแองกูลาร์ ฉันทำงานเกี่ยวกับ Angular แล้ว

ฉันต้องการผูกรายการดร็อปดาวน์แบบซ้อนสำหรับJsonข้อมูลที่มาจากเซิร์ฟเวอร์โดยการเรียก Rest Api

ข้อมูลมีหนึ่งคุณลักษณะLgLevelระบุระดับในลำดับชั้นของกลุ่ม ผู้ปกครองจะมีlevel=0, ทันทีChild=1, Grandchild=2และอื่น ๆ ChildและGrandchildมีParentLocationGroupฟิลด์ซึ่งแสดงภายในเมนูหลักเมนูย่อยจะมี

นี่คือjsonข้อมูลของฉัน ฉันมีข้อมูลจำนวนมาก แต่ไม่แสดงทั้งหมด

{
"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"
}
}

ฉันพยายามพัฒนา แต่ฉันพบตัวอย่างทั้งหมดของbootstrapข้อมูลคงที่ในhtmlไฟล์และCSSไฟล์แยกที่ซับซ้อนสำหรับฉัน

TypeScriptผมต้องการที่จะทำแบบไดนามิกโดยใช้ ฉันจะเริ่มทำงานกับมันได้อย่างไร


ประการแรกรูปแบบข้อมูลเป็นและไม่ได้XML JSONคุณสามารถเพิ่มสิ่งที่คุณได้ลองด้วยหรือไม่ อาจมีรายละเอียดเพิ่มเติมเกี่ยวกับวิธีการที่คุณใช้
vatz88

@ vatz88 - ใช่นี่คือ xml ที่เพิ่งวางจากบุรุษไปรษณีย์ ฉันลองใช้htmlรหัสที่มีรายการซ้อนอยู่คงที่ ฉันจะพยายามแก้ไขและจะโพสต์Jsonข้อมูล คุณจะไม่ชอบสิ่งที่ฉันได้ลอง :)
Arvind Chourasiya

คุณไม่ต้องกังวลกับสิ่งที่คุณได้ทำไว้แล้ว วิธีการคือ - hardcode ข้อมูลในไฟล์ ts ใน html ทำการผูกข้อมูลตามข้อมูลที่คุณต้องทำการดรอปดาวน์ เมื่อตรรกะนั้นถูกต้องให้ทำงานในการรับข้อมูลแบบไดนามิกแล้วปล่อยให้เชิงมุมกับการผูกทำมายากล
vatz88

@ vatz88 - รหัสคงที่ของฉันอยู่ในhtmlไฟล์ ฉันมีความคิดที่จะเริ่มต้น คุณสามารถช่วยฉันออก
Arvind Chourasiya

@ArvindChourasiya มีลูกจำนวนมากของ LgLevel 1 วิธีการระบุว่าหลานของ LgLevel 2 เป็นลูกคนใด?
Satish Pai

คำตอบ:


4

นี่คือตัวอย่างโค้ดที่คุณต้องการตามข้อมูลระดับซ้อนจากข้อมูล json ของคุณ ตอนนี้คุณสามารถวนลูปข้อมูล json ที่จัดรูปแบบใน DOM โดยใช้ข้อมูลโมเดล ฉันหวังว่าสิ่งนี้จะช่วยคุณในการสร้างเมนูแบบเลื่อนลงหลายระดับ

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

    <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>

ตามข้อมูลการตอบกลับของเซิร์ฟเวอร์ของคุณจะจัดระเบียบข้อมูลโมเดล เปลี่ยนรูปแบบ json แล้ว ( __textเป็น#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" : []
  }

คุณช่วยกรุณาโพสต์ไฟล์. html ด้วยเช่นกัน
Arvind Chourasiya

@ArvindChourasiya คุณต้องการเลือกแท็กดร็อปดาวน์หรือเพียงแค่ดรอปดาวน์ ( ลิงก์ )?
Yaseer

ฉันต้องการมันแสดงในตัวเลือก dolor จากลิงค์ด้านบน
Arvind Chourasiya

@ArvindChourasiya ฉันอัพเดทโพสต์ด้วย html
Yaseer

ฉันสับสนเล็กน้อยกับรหัสของคุณ คุณไม่ได้ใช้งานgetDataที่ไหน คุณช่วยกรุณาตรวจสอบรหัสของคุณและเพิ่มการเปิดและปิด
Arvind Chourasiya

4

ดูเหมือนว่าคุณมีคำตอบอื่นที่ตรงกับความต้องการของคุณแล้ว แต่วิธีนี้เอาฉันมาบางครั้ง ดังนั้นตัดสินใจที่จะโพสต์มันต่อไป

ข้อมูลโค้ดด้านล่างนี้ใช้เพื่อสร้างแผนผังเช่นโครงสร้างของข้อมูลลำดับชั้นพาเรนต์ - ลูก:

  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;
  }

ข้อมูลที่รวบรวมจะถูกส่งผ่านเป็นอินพุตไปยัง dropdownคอมโพเนนต์ซึ่งแสดงเป็นเมนูดร็อปดาวน์หลายระดับ

วิธีแก้ปัญหานี้น่าจะใช้ได้ผลกับเด็กทุกระดับ dropdownองค์ประกอบที่สามารถแก้ไขได้จะเปลี่ยนวิธีที่ข้อมูลจะถูกแสดงผลตามความต้องการของคุณ

ฉันใช้htmlและcssสำหรับเมนูแบบเลื่อนลงหลายระดับจากที่นี่:
https://phppot.com/css/multilevel-dropdown-menu-with-pure-css/
รหัสเพื่อปิดเมนูแบบเลื่อนลงเมื่อคลิกจากคำตอบนี้:
https: //stackoverflow.com/a/59234391/9262488

หวังว่าคุณจะพบว่ามีประโยชน์นี้


ฉันตรวจสอบรหัสของคุณแล้ว มันใช้งานได้ดี ขอบคุณสำหรับการโพสต์คำตอบ คุณช่วยบอกฉันทีว่าคุณรับข้อมูลของฉันได้อย่างไร สำหรับคำขอ http (mocky.io)
Arvind Chourasiya

Mocky เป็นเครื่องมือออนไลน์สำหรับการสร้างส่วนที่เหลือจำลอง ฉันเอาข้อมูลที่คุณโพสต์และใช้มันเพื่อสร้างส่วนที่เหลือ API โดยใช้จำลอง
NiK648

1

ทำไมไม่สร้างองค์ประกอบต้นไม้และผูกอินพุตกับมันซ้ำ?

ทางออกที่นำเสนอคือ

  • ผู้ไม่เชื่อเรื่องพระเจ้าอย่างลึกซึ้ง - มันจะใช้ได้กับหลายระดับในแผนผังข้อมูลของคุณ (แม้ว่ามันจะเปลี่ยน Ad-hoc)
  • ค่อนข้างมีประสิทธิภาพ - O(n)มันรวบรวมข้อมูลของคุณใน

ก่อนออกแบบโมเดลข้อมูล - มันต้องเป็นโครงสร้างทรีโหนด:

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[]
}

จากนั้นรวมข้อมูลของคุณในองค์ประกอบระดับบนสุด (หรือดีกว่า - ในบริการข้อมูลของคุณคุณควรจะสรุปได้อย่างง่ายดาย):

// 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, 
      []
    );
  }
}

และสร้างองค์ประกอบ flyout ไดนามิกที่เกิดขึ้นอีก:

// 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[];
}

วิธีการแก้ปัญหาไม่ได้ทดสอบ แต่มันจะชี้ให้คุณในทิศทางที่ถูกต้อง ...

หวังว่านี่จะช่วย :-) นิดหน่อย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.