2016-07-04 12 views
8

Supponiamo che io ho una classe dipendente che sembra qualcosa di simile:Angular2: come trasformare il mio modello ad albero per adattarlo ad un'interfaccia diversa?

export class Employee { 

    jobTitle: string; 
    firstName: string; 
    lastName: string; 

    boss: Employee; 
    workers: Employee[]; 

    constructor(jobTitle: string, firstName: string, lastName: string){ 
     this.jobTitle = jobTitle; 
     this.firstName = firstName; 
     this.lastName = lastName; 
    } 

    public addWorker(worker: Employee){ 
     this.wokers.push(worker); 
     worker.boss = this; 
    } 

} 

Supponiamo di avere iniziali Employee s che sembrano qualcosa di simile:

function getInitialStaff(): Employee { 

    let headWaiter: Employee = new Employee("Head Waiter", "Sarah", "Hilton"); 
    headWaiter.addWorker(new Employee("Bus Boy", "Joe", "BeefEater")); 
    headWaiter.addWorker(new Employee("Waiter", "Randy", "Rainman")); 

    let headCheif: Employee = new Employee("Head Cheif", "Phil", "Yorstomux"); 
    headWaiter.addWorker(new Employee("Dishwasher", "Andy", "Shark")); 

    let owner: Employee = new Employee("Owner", "Boris", "Laughington"); 
    owner.addWorker(headWaiter); 
    owner.addWorker(headCheif); 
    return owner; 
} 

Possiamo anche assumere che a volte i dipendenti saranno essere assunto o licenziato. Qualcosa sulla falsariga di questo:

window.setTimeout(()=>{ 
    let someEmployee: Employee = /* Some existing employee */ 
    someEmployee.addWorker("someTitle", "someName", "someLastName"); 
}, someAmountOfTime); 

Voglio visualizzare i dipendenti in un PrimeNg tree.

L'albero widget di richiede che i dati da visualizzare conforme all'interfaccia TreeNode, che assomiglia a questo:

export interface TreeNode { 
    label?: string; 
    data?: any; 
    icon?: any; 
    expandedIcon?: any; 
    collapsedIcon?: any; 
    children?: TreeNode[]; 
    leaf?: boolean; 
} 

Domanda principale: Senza cambiare la mia classe Employee, qual è il modo migliore per trasformare i dati in TreeNodes?


Cose che io sto pensando:

  • Quando aggiungo un nuovo dipendente, voglio mantenere il mio stato albero (ciò che è aperto, ciò che è stato selezionato, ecc)
  • ho bisogno essere in grado di recuperare facilmente il dipendente che è attualmente selezionato.
  • Sto cercando di evitare di mantenere due modelli duplicati.
  • voglio approfittare di rilevamento delle modifiche di Angular2 in un ragionevole, ma il modo scalabile

Questo è ciò che il mio EmployeeTree componente assomigliare al momento:

@Component({ 
    selector: 'employee-tree', 
    template: ` 
     <div> 
      <p-tree> 
       /* Open Question, I need to transform owner and then tie the resulting TreeNode to the tree */ 
      </p-tree> 
     </div> 
    ` 
    directives: [ Tree ] 
}) 
export class EmployeeTree { 
    @Input() 
    private owner: Employee; 
} 

Opzione 1 - Creare una pipe che trasformerà un dipendente in TreeNode

Credo che sarebbe lasciare il mio modello simile a questo:

<p-tree [value]="owner | convertToTreeNode"></p-tree> 

e vorrei creare un tubo che ha fatto qualcosa di simile:

@Pipe({name: 'convertToTreeNode'}) 
export class ToTreeNode implements PipeTransform { 
    transform(employee: Employee): TreeNode { 

     let treeNode: TreeNode = { 
      label: employee.firstName + " " + employee.lastName, 
      data: employee, 
      children: [] 
     }; 

     employee.workers.forEach(worker => { 
      treeNode.children.push(this.transform(worker)); 
     }) 

     return treeNode; 

    } 
} 

Pro/Contro:

  • Questo sfrutta il rilevamento del cambio angolare
  • Se si tratta di un tubo puro, potrebbero perdere le modifiche
  • Se si tratta di un tubo impura, può essere troppo pesante
  • Lascia la componente molto pulito e delega la responsabilità al tubo
  • Non sono sicuro se questo sarà preservare il mio stato gui (quello che viene selezionato e ciò che è aperto/chiuso) quando un nuovo articolo si aggiunge

Opzione 2 - All'interno della componente di mantenere una struttura separata per l'albero

@Component({ 
    selector: 'employee-tree', 
    template: ` 
     <div> 
      <p-tree [data]="employeeTree"> 
      </p-tree> 
     </div> 
    ` 
    directives: [ Tree ] 
}) 
export class EmployeeTree { 
    @Input() 
    private owner: Employee; 

    private employeeTree: TreeNode; 

    // TODO - Somehow watch the owner for changes (how?) and then repopulate the employeeTree 
} 

Penso che potrei far sì che il Dipendente emetta un evento che gocciola quando cambia. Questo potrebbe darmi qualcosa a cui aggrapparmi.


In generale, qual è il modo migliore di utilizzare Angular2 per fare qualcosa di simile.

In sintesi, voglio usare un widget che si aspetta i dati in un formato leggermente più diverso rispetto a quello che sto riporlo in. Qual è il modo angular2 standard per massaggiare i miei dati nel widget di? C'è una speciale salsa angular2 che mi aiuterà qui? Devo mantenere due modelli separati? Potenzialmente il mio albero potrebbe contenere 100 o forse 1000 di elementi, quindi sono piuttosto interessato alle prestazioni.

risposta

0

Vorrei usare Lodash map.Ecco il loro esempio in scatola:

import * as _ from 'lodash'; 
var users = [ 
    { 'user': 'barney' }, 
    { 'user': 'fred' } 
]; 

// The `_.property` iteratee shorthand. 
_.map(users, 'user'); 
// => ['barney', 'fred'] 

Ecco la mia svolta su che:

let emplData = [ 
 
     { "jobTitle": "Paperboy", 
 
      "firstName": "Fred", 
 
      "lastName": "Bloggs" 
 
     }, 
 
     { "jobTitle": "Tea boy", 
 
      "firstName": "Charlie", 
 
      "lastName": "Creamslice" 
 
     }   
 
    ] 
 
    let resEl = document.getElementById("result"); 
 
    resEl.innerText =JSON.stringify(emplData.map(buildEmployeeNamesOnlyAndAddSeqNo)); 
 

 
    function buildEmployeeNamesOnlyAndAddSeqNo({firstName,lastName},index) { 
 
     return {seqNo:index, firstName, lastName} 
 
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.2/lodash.js"></script> 
 

 
    <div id="result"> 
 
     
 
    </div>

0

Si può avere sottoclasse di Employee in cui esse sono conformi ai TreeNode

Poi nel componente

@Component({ 
     selector: 'employee-tree', 
     template: ` 
      <div> 
       <p-tree [data]="employeeNode.label"> 
       </p-tree> 
      </div> 
     ` 
     directives: [ Tree ] 
    }) 
    export class EmployeeNode extends Employee implements TreeNode { 

     // -- No need for this anymore -- @Input() private owner: EmployeeNode; 
     @Input() private jobTitleInput: String; 
     @Input() private firstNameInput: String; 
     @Input() private lastNameInput: String; 

     constructor(){ 
      super(jobTitleInput, firstNameInput, lastNameInput); 

      // Populate TreeNode here for example label from TreeNode 
      this.label = `${firstName} ${lastName}`; 
     } 

     //private employeeTree: TreeNode; -- No need for TreeNode object any more as EmployeeNode contains both TreeNode and Employee 

     // TODO - Somehow watch the owner for changes (how?) and then repopulate the employeeTree : Just add a setter for each property 
of Employee that you want to also affect TreeNode field and inside that setter update in your EmployeeNode class the field of TreeNode Interface like 'this.label = 'updated value' 
    } 
Problemi correlati