Cách tạo danh sách thả xuống đa cấp và liên kết với dữ liệu đến từ máy chủ


15

Tôi rất mới với Angular. Tôi đã có một số công việc trên Angular.

Tôi cần liên kết danh sách thả xuống Nested cho Jsondữ liệu đến từ máy chủ bằng cách gọi Rest Api.

Dữ liệu có một thuộc tính LgLevel, Chỉ định cấp độ trong hệ thống phân cấp của nhóm. Cha mẹ sẽ có level=0, ngay lập tức Child=1, Grandchild=2và như vậy. ChildGrandchildParentLocationGrouptrường, hiển thị bên trong menu cha, menu con sẽ ở đó.

Đây là jsondữ liệu của tôi . Tôi có dữ liệu lớn nhưng không hiển thị tất cả.

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

Tôi đã thử nó để phát triển nhưng tôi tìm thấy tất cả các ví dụ về bootstrapdữ liệu tĩnh trong htmltệp và CSStệp riêng biệt gây phức tạp cho tôi.

Tôi muốn làm điều đó một cách linh hoạt bằng cách sử dụng TypeScript. Làm thế nào tôi có thể bắt đầu làm việc trên nó.


Thứ nhất, định dạng dữ liệu là XMLvà không JSON. Bạn cũng có thể thêm bất cứ điều gì bạn đã cố gắng? Có thể chi tiết hơn cách tiếp cận bạn đã áp dụng.
vatz88

@ vatz88 - Vâng, đây là xml vừa được dán từ người đưa thư. Tôi đã thử htmlmã có danh sách lồng nhau tĩnh. Tôi sẽ cố gắng chỉnh sửa nó và sẽ đăng Jsondữ liệu. Bạn sẽ không thích những gì tôi đã thử :)
Arvind Chourasiya

Bạn không phải lo lắng những gì bạn đã mã hóa cho đến nay. Cách tiếp cận sẽ là - mã hóa dữ liệu trong tệp ts, trong html tạo các ràng buộc theo dữ liệu bạn có để hiển thị danh sách thả xuống. Một khi logic đó là chính xác, hãy làm việc để có được dữ liệu một cách linh hoạt, và sau đó để cho các góc với sự ràng buộc làm điều kỳ diệu.
vatz88

@ vatz88 - Mã tĩnh của tôi đã có trong htmltệp. Tôi có ý tưởng để bắt đầu nó. Bạn có thể giúp tôi ra.
Arvind Chourasiya

@ArvindChourasiya có nhiều đứa con của LgLevel 1, làm thế nào để xác định cháu của LgLevel 2 thuộc về đứa trẻ nào?
Satish Pai

Câu trả lời:


4

Đây là một mẫu được mã hóa mà bạn cần theo dữ liệu mức lồng nhau từ dữ liệu json của bạn. Bây giờ bạn có thể lặp dữ liệu json được định dạng trong DOM bằng dữ liệu mô hình . Tôi hy vọng điều này sẽ giúp bạn tạo ra một trình đơn thả xuống đa cấp

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

Tập tin 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>

Theo dữ liệu phản hồi máy chủ của bạn tổ chức dữ liệu mô hình. Phản hồi định dạng json đã thay đổi ( _ lòng thành #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" : []
  }

Bạn có thể vui lòng gửi tập tin .html là tốt.
Arvind Chourasiya

@ArvindChourasiya Bạn có cần chọn thả xuống thẻ hoặc chỉ thả xuống ( liên kết )?
Yaseer

Tôi cần như nó được hiển thị trong tùy chọn dolor từ liên kết trên.
Arvind Chourasiya

@ArvindChourasiya Tôi đã cập nhật bài đăng bằng html
Yaseer

Tôi hơi nhầm lẫn với mã của bạn. Bạn không sử dụng getDatabất cứ nơi nào. Bạn có thể vui lòng kiểm tra mã của bạn một và thêm mở và đóng.
Arvind Chourasiya

4

Có vẻ như bạn đã có một câu trả lời khác đáp ứng yêu cầu của bạn. Nhưng giải pháp này đôi khi tôi đã đưa ra. Vì vậy, quyết định gửi nó anyway.

Đoạn mã dưới đây được sử dụng để xây dựng cấu trúc giống như cây của dữ liệu phân cấp cha-con:

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

Dữ liệu tổng hợp được truyền dưới dạng đầu vào cho một dropdownthành phần làm cho nó trở thành menu thả xuống đa cấp.

Giải pháp này được cho là sẽ làm việc cho bất kỳ cấp độ của trẻ em. Thành dropdownphần có thể được sửa đổi để thay đổi cách hiển thị dữ liệu theo yêu cầu của bạn.

Tôi đã lấy htmlcsscho menu thả xuống đa cấp từ đây:
https://phppot.com/css/multilevel-dropdown-menu-with-pure-css/
Mã để đóng trình đơn thả xuống khi nhấp vào bên ngoài từ câu trả lời này:
https: //stackoverflow.com/a/59234391/9262488

Hy vọng bạn tìm thấy điều này hữu ích.


Tôi đã kiểm tra mã của bạn. Nó đang hoạt động. Cảm ơn bạn đã gửi câu trả lời. Bạn có thể vui lòng cho tôi biết làm thế nào bạn nhận được dữ liệu của tôi. cho yêu cầu http (mocky.io).
Arvind Chourasiya

Mocky là một công cụ trực tuyến để tạo api mock rest. Tôi lấy dữ liệu bạn đã đăng và sử dụng nó để tạo ra một api còn lại bằng cách sử dụng mocky.
NiK648

1

Tại sao không tạo một thành phần cây và liên kết đầu vào với nó một cách đệ quy?

Giải pháp đề xuất là

  • không chuyên sâu - nó sẽ hoạt động cho bất kỳ số cấp nào trong cây dữ liệu của bạn (ngay cả khi nó thay đổi đặc biệt)
  • khá hiệu quả - nó tổng hợp dữ liệu của bạn trong O(n).

Đầu tiên thiết kế mô hình dữ liệu - nó phải là cấu trúc nút cây:

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

Sau đó, tổng hợp dữ liệu của bạn trong thành phần cấp cao nhất (hoặc thậm chí tốt hơn - trong dịch vụ dữ liệu của bạn; bạn sẽ có thể trừu tượng hóa đủ dễ dàng):

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

Và tạo thành phần flyout động lặp lại:

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

Giải pháp không được thử nghiệm nhưng nó sẽ chỉ cho bạn đi đúng hướng ...

Hy vọng điều này sẽ giúp một chút :-)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.