angulardart / angular

Fast and productive web framework provided by Dart
https://pub.dev/packages/angular
MIT License
1.83k stars 232 forks source link

template recursion without Map support #1918

Open insinfo opened 3 years ago

insinfo commented 3 years ago

how to deal with recursion in Template without Map support? I have a project that I am migrating from AngularDart 5.3.1 to AngularDart 6.0.0-alpha + 1, which uses recursion in the Template to create a Menu recursively, it works well in AngularDart 5.3.1, more in AngularDart 6 Map support was removed and now I don't know how to pass the context map

<div *ngIf="list?.isNotEmpty == true" class="card card-sidebar-mobile">
            <ul #ulroot class="nav nav-sidebar" data-nav-type="accordion">
                <template #recursiveList let-list>                  

                    <li class="nav-item " *ngFor="let item of list; let i = index"
                      [class.nav-item-submenu]="item.children.length > 0" [class.nav-item-open]="item.level == 0">

                        <a #anchorElement [attr.data-rota]="item.rota" class="nav-link item"
                            (click)="toogleSubMenuhtml(anchorElement, item)"
                            [class.nav-link-level-1]="item.level == 1"
                             [hidden]="item.filter == false">
                            <i [class]="item.icone" *ngIf="item.icone != null"></i>
                            <span>{{item.label}}</span>
                        </a>
                        <ul class="nav nav-group-sub" *ngIf="item.children.length > 0"
                            [style.display]="item.isCollapse==false  ? 'block': 'none'">
                            <!--<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: item.children }">-->
                            <ng-container *ngTemplateOutlet="recursiveList">
                            </ng-container>
                        </ul>
                    </li>
                </template>
                <!-- <ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: list }"></ng-container> -->
                <ng-container *ngTemplateOutlet="recursiveList"></ng-container>
            </ul>          
        </div>

image

ygordaudt commented 3 years ago

I'm with the same problem.

I found a solution , but I'm don't know it is the best way to fix the problem.

This solution unfortunately causes Angular to redraw objects on the screen all the time, since, as the property is a computed function, and Angular's change detector causes the ngTemplateOutlet to be called at all times.


extension TemplateOutletContextForRender on RList {
  // this is for the compatibility with the Angular 6.0
 //ngTemplateOutlet <ng-container *ngTemplateOutlet="recursiveList; context: item.contextForRender ">
  Map<String, dynamic> get templateOutletContext {
    return {'\$implicit': this};
  }
}

In component Controller

class MenuItem {
  int id;
  int idPai;
  String rota;
  String label;
  String icone;
  String cor;
  int ordem;
  bool ativo;
  int idSistema;
  RList<MenuItem> children = RList<MenuItem>();
  int level;
  bool filter;
  MenuItem parent;
  bool isCollapse = true;

  bool hasChilds(MenuItem item) {
    return item.children?.isNotEmpty == true;
  }

  //this is for the compatibility with the Angular 6.0
// ngTemplateOutlet <ng-container *ngTemplateOutlet="recursiveList; context: item.templateOutletContext ">
  Map<String, dynamic> get templateOutletContext => {'\$implicit': children};

  bool finded(String _search_query, MenuItem item) {
    var item_title = Utils.removerAcentos(item.label).toLowerCase();
    //return item_title.contains(_search_query);
    return (item_title.indexOf(_search_query) != -1);
  }

  MenuItem clone() {
    return MenuItem.fromJson(toJson());
  }

  MenuItem.fromJson(Map<String, dynamic> json) {
    try {
      id = Utils.isNotNullOrEmptyAndContain(json, 'id') ? json['id'] : null;
      idPai = Utils.isNotNullOrEmptyAndContain(json, 'idPai') ? json['idPai'] : null;
      label = Utils.isNotNullOrEmptyAndContain(json, 'label') ? json['label'] : null;
      icone = Utils.isNotNullOrEmptyAndContain(json, 'icone') ? json['icone'] : null;
      ordem = Utils.isNotNullOrEmptyAndContain(json, 'ordem') ? json['ordem'] : null;
      ativo = Utils.isNotNullOrEmptyAndContain(json, 'ativo') ? json['ativo'] : null;
      idSistema = Utils.isNotNullOrEmptyAndContain(json, 'idSistema') ? json['idSistema'] : null;
      rota = Utils.isNotNullOrEmptyAndContain(json, 'rota') ? json['rota'] : '#';
      level = Utils.isNotNullOrEmptyAndContain(json, 'level') ? json['level'] : null;
      if (Utils.isNotNullOrEmptyAndContain(json, 'nodes')) {
        children = RList<MenuItem>();
        json['nodes'].forEach((v) {
          children.add(MenuItem.fromJson(v));
        });
      }
    } catch (e) {
      print('MenuItem.fromJson: ${e}');
    }
  }

  Map<String, dynamic> toJson() {
    final json = <String, dynamic>{};
    if (id != null) {
      json['id'] = id;
    }
    json['idPai'] = idPai;
    json['label'] = label;
    json['icone'] = icone;
    json['cor'] = cor;
    json['ordem'] = ordem;
    json['idSistema'] = idSistema;
    json['rota'] = rota;
    json['level'] = level;

    if (children != null && children.isNotEmpty) {
      json['nodes'] = children.map((v) => v.toJson()).toList();
    }

    return json;
  }

}

RList<MenuItem> list = RList<MenuItem>();