typescript - Angular 8 - Sortarea unui component de arbore recursiv după tipul valorii


Având următorul obiect:

const data = {
    "root": {
         "title": "Shapes",
         "shapes": { ... },
         "description": "All sorts of geometrical whizz"
    }
}

Ar trebui să găsesc o modalitate de a sorta acest obiect astfel încât cheile cu obiecte să apară deasupra cheilor cu stringuri, așa cum se vede mai jos:

const data = {
    "root": {
         "shapes": { ... },
         "title": "Shapes",
         "description": "All sorts of geometrical whizz"
    }
}

Ceea ce am încercat a fost funcția sort():

const sorted = Object.values(root).sort((v) => typeof v === 'object' ? -1 : 1)

Deși acest lucru funcționează pentru a sorta valorile păstrând obiectul rădăcină intact, cheile se pierd în acest nou array sorted...

[
    {...}, 
    "Shapes", 
    "All sorts of geometrical whizz"
]

...în timp ce trebuie păstrat ca un obiect deoarece cheile sunt folosite de un component Tree recursiv, unde sortarea în acest mod este inutilă:

<ng-template *ngFor="let key of Object.keys(data)">
    <div *ngIf="typeof key === 'object'>
        <button (click)="show(value)">
            {{key}} 
        </button>
        <this-template [data]="data[key]">
    </div>

    <div *ngIf="typeof key === 'string'>
        <button (click)="show(value)">
            {{key}} 
        </button>
    </div>
</ng-template>

deoarece componenta va continua să se redea pe baza structurii root:

↓ root
    |- title
    |- > shapes
    |- description

în timp ce structura dorită este aceasta:

↓ root
    |- > shapes
    |- title
    |- description

Astfel, pentru a defini problema printr-o singură întrebare;

Cum aș putea să sortezi un obiect după tipul valorii cheii, pentru a reda un component recursiv care să afișeze mai întâi elementele cu obiecte înaintea elementelor cu șiruri de caractere?

Răspuns #1

Folosind Object.entries și un reduce ar trebui să poți obține rezultatul dorit:

const data = {
  "root": {
    "shapes": { /* ... */ },
    "title": "Shapes",
    "description": "All sorts of geometrical whizz"
  }
}

const sorted = Object.entries(data.root)
  .sort(([key, v]) => typeof v === 'object' ? -1 : 1)
  .reduce((newObj, [key, v]) => ({ ...newObj, [key]: v }), {})
  
console.log(sorted)

Răspuns #2

O soluție nu foarte elegantă, dar rapidă ar fi

    const data = {
      "root": {
           "title": "Shapes",
           "shapes": { a: 'name' },
           "description": "All sorts of geometrical whizz"
      }
  };

  const object = {};

  Object.values(data.root).forEach((a, i) => {
    // console.log(a);
    if (typeof(a) === 'object') {
      object[Object.keys(data.root)[i]] = a;
    }
  });

  Object.values(data.root).forEach((a, i) => {
    // console.log(a);
    if (!(typeof(a) === 'object')) {
      object[Object.keys(data.root)[i]] = a;
    }
  });
  console.log(object);