2017-02-16 6 views
1

Ich navigiere von einer Ansicht (nennen Sie BestSellersView) zu einer anderen (BookDetailsView). Es gibt mehrere verschiedene "Eltern" -Sichten, die zu "Buchdetails" navigieren können und alle müssen das Buch, das angezeigt werden soll, an die nächste Ansicht weiterleiten. Ich möchte die Quellansicht nicht in die Detailansicht injizieren, wie einige Threads vorschlagen, da mein Konstruktor mit jeder neuen Ansicht wächst, die die Detailsubansicht verwendet.Daten in noch nicht geladene Ansicht in Aurelia übergeben

Ich versuche, den Ereignisaggregator zu verwenden, aber aufgrund des Lebenszyklus der Dinge bekomme ich immer einen leeren Detailbildschirm, wenn ich das erste Mal navigiere. Wenn ich zuerst zur Ansicht 'Buchdetails' navigiere, wurde die ViewDetailsMessage noch nicht abonniert, bevor der Publisher (Bestseller) die Nachricht sendet. Da ich mein Viewmodel auf Singleton eingestellt habe, funktionieren die nachfolgenden Klicks gut (da die Detailansicht bereits erstellt und dem Event zugewiesen wurde).

Wie kann ich dieses Problem mit Hühnereiern in Aurelia umgehen?

bearbeiten 01

Hier ist, was ich tat, als ich ein Problem hatte:

Master.ts:

import { JsonServiceClient } from "servicestack-client"; 
import { 
    ListPendingHoldingsFiles, 
    ListPendingHoldingsFilesResponse, 
    SendHoldings, 
    PositionFileInfo 
} from "../holdingsManager.dtos"; 
import { inject, singleton } from "aurelia-framework"; 
import { Router } from "aurelia-router"; 
import { EventAggregator } from "aurelia-event-aggregator"; 
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage"; 

@singleton() 
@inject(Router, EventAggregator) 
export class Pending { 
    router: Router; 
    positions: PositionFileInfo[]; 
    client: JsonServiceClient; 
    eventAgg: EventAggregator; 

    constructor(router, eventAggregator) { 
     this.router = router; 
     this.eventAgg = eventAggregator; 
     this.client = new JsonServiceClient('/'); 
     var req = new ListPendingHoldingsFiles(); 
     this.client.get(req).then((getHoldingsResponse) => { 
      this.positions = getHoldingsResponse.PositionFiles; 
     }).catch(e => { 
      console.log(e); // "oh, no!" 
     }); 
    } 

    openHoldings(positionInfo) { 
     this.eventAgg.publish(new GetPendingPositionMessage(positionInfo)); 
     this.router.navigate('#/holdings'); 
    } 
} 

Child.ts:

import { JsonServiceClient } from "servicestack-client"; 
import { inject, singleton } from "aurelia-framework"; 
import { Router } from 'aurelia-router'; 
import { EventAggregator } from "aurelia-event-aggregator"; 
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage"; 
import { 
    GetPendingHoldingsFile, 
    GetPendingHoldingsFileResponse, 
    Position, 
    PositionFileInfo 
} from "../holdingsManager.dtos"; 

@singleton() 
@inject(Router, EventAggregator) 
export class Holdings { 
    router: Router; 
    pendingPositionFileInfo: PositionFileInfo; 
    position: Position; 
    client: JsonServiceClient; 
    eventAgg: EventAggregator; 

    constructor(router, eventAggregator) { 
     this.router = router; 
     this.eventAgg = eventAggregator; 
     this.eventAgg.subscribe(GetPendingPositionMessage, 
      message => { 
       this.pendingPositionFileInfo = message.fileInfo; 
      }); 
    } 

    activate(params, routeData) { 
     this.client = new JsonServiceClient('/'); 
     var req = new GetPendingHoldingsFile(); 
     req.PositionToRetrieve = this.pendingPositionFileInfo; 
     this.client.get(req).then((getHoldingsResponse) => { 
      this.position = getHoldingsResponse.PendingPosition; 
     }).catch(e => { 
      console.log(e); // "oh, no!" 
     }); 
    } 
} 

Hier ist was ich gerade mache:

master.ts

import { JsonServiceClient } from "servicestack-client"; 
import { 
    ListPendingHoldingsFiles, 
    ListPendingHoldingsFilesResponse, 
    PositionFileInfo 
} from "../holdingsManager.dtos"; 
import { inject, singleton } from "aurelia-framework"; 
import { Router } from "aurelia-router"; 
import { EventAggregator } from "aurelia-event-aggregator"; 
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage"; 
import { SetPendingPositionMessage } from "../common/SetPendingPositionMessage"; 

@singleton() 
@inject(Router, EventAggregator) 
export class Pending { 
    router: Router; 
    eventAgg: EventAggregator; 
    positions: PositionFileInfo[]; 
    client: JsonServiceClient; 
    fileInfo: PositionFileInfo; 

    constructor(router, eventAggregator) { 
     this.router = router; 
     this.eventAgg = eventAggregator; 
     this.eventAgg.subscribe(GetPendingPositionMessage,() => { 
      this.eventAgg.publish(new SetPendingPositionMessage(this.fileInfo)); 
     }); 
    } 

    activate(params, routeData) { 
     this.client = new JsonServiceClient('/'); 
     var req = new ListPendingHoldingsFiles(); 
     this.client.post(req).then((getHoldingsResponse) => { 
      this.positions = getHoldingsResponse.PositionFiles; 
     }).catch(e => { 
      console.log(e); // "oh, no!" 
     }); 
    } 

    openHoldings(positionInfo) { 
     this.fileInfo = positionInfo; 
     this.router.navigate('#/holdings'); 
    } 
} 

child.ts

import { JsonServiceClient } from "servicestack-client"; 
import { inject, singleton } from "aurelia-framework"; 
import { Router } from 'aurelia-router'; 
import { 
    GetPendingHoldingsFile, 
    GetPendingHoldingsFileResponse, 
    Position, 
    SendHoldings, 
    PositionFileInfo 
} from "../holdingsManager.dtos"; 
import { EventAggregator } from "aurelia-event-aggregator"; 
import { GetPendingPositionMessage } from "../common/GetPendingPositionMessage"; 
import { SetPendingPositionMessage } from "../common/SetPendingPositionMessage"; 
import { GetDeliveredPositionMessage } from "../common/GetDeliveredPositionMessage"; 
import { SetDeliveredPositionMessage } from "../common/SetDeliveredPositionMessage"; 

@singleton() 
@inject(Router, EventAggregator) 
export class Holdings { 
    router: Router; 
    pendingPositionFileInfo: PositionFileInfo; 
    position: Position; 
    client: JsonServiceClient; 
    eventAgg: EventAggregator; 

    constructor(router, eventAggregator) { 
     this.router = router; 
     this.eventAgg = eventAggregator; 
     this.eventAgg.subscribe(SetPendingPositionMessage, message => this.getPositionData(message.fileInfo)); 
     this.eventAgg.subscribe(SetDeliveredPositionMessage, message => this.getPositionData(message.fileInfo)); 
    } 

    getPositionData(fileInfo) { 
     this.position = null; 
     this.client = new JsonServiceClient('/'); 
     var req = new GetPendingHoldingsFile(); 
     req.PositionToRetrieve = fileInfo; 
     this.client.post(req).then((getHoldingsResponse) => { 
      this.position = getHoldingsResponse.PendingPosition; 
     }).catch(e => { 
      console.log(e); // "oh, no!" 
     }); 
    } 

    activate(params) { 
     this.eventAgg.publish(new GetPendingPositionMessage()); 
     this.eventAgg.publish(new GetDeliveredPositionMessage()); 
    } 

    sendHoldings() { 
     var req = new SendHoldings(); 
     this.client.get(req).then((sendHoldingsRepsonse) => { 
      console.log("SUCCESS!"); // "oh, no!" 
     }).catch(e => { 
      console.log(e); // "oh, no!" 
     }); 
    } 
} 

Ich brauche ein bisschen Logik auf die Activate-Methode des Kindes füge ich für den richtigen Eltern Bestände Datei fragen zu gewährleisten.

+0

Wir müssen etwas Code sehen, um zu sehen, wie Sie Dinge tun, um zu sehen, wie wir helfen können. –

+0

@KellyEthridge Ich habe Code zum Vergleich hinzugefügt. – Bitfiddler

Antwort

1

Klingt so, als müssten Sie den Status zwischen den Ansichten teilen. Ich verwende eine Klasse, die in alle Ansichten eingefügt wird, die den Status teilen möchten. Standardmäßig sind alle injizierten Objekte Singletons, wodurch es einfach ist, den Status zu teilen. Ein sehr einfaches Beispiel könnte sein (in Typoskript):

statestore.ts

export class StateStore { 
    state: any; 
} 

masterview.ts

autoinject() 
export class MasterView { 
    constructor(private store: StateStore){ 
    } 

    doSomething(): void { 
     this.store.state = "some value"; 
     // navigate to detail view 
    } 
} 

detailview.ts

autoinject() 
export class DetailView { 
    sharedValue: any; 

    constructor(store: StateStore) { 
     this.sharedValue = store.state; 
    } 
} 

Dies wird eine Aktie Instanz von zwischen Ansichten ermöglicht den Status leicht geteilt werden.

1

Meine aktuelle Lösung, wenn auch nicht so schön, wie ich es sein möchte wie folgt:

Quellenansicht (bestSellersView) ein Singleton ist und abonniert „GetCurrentBookMessage“. Wenn ein Benutzer ein Buch auswählt, speichert die Quelle es lokal und navigiert zur "BookDetailsView". Die BookDetailsView ist aufgebaut, abonniert eine "SetCurrentBookMessage" und, wenn sie aktiviert ist, sendet sie eine GetCurrentBookMessage. Die Quellansicht antwortet mit einer "SetCurrentBookMessage".

Dies wird chaotisch mit mehreren Quellen und ich muss einen Weg haben, um zu lösen, wo die Navigation kam, um die "richtige" Quelle auszuwählen, aber für heute funktioniert das.

bearbeiten 01 Ich habe auch versucht, von all den Fall Aggregator Sachen loszuwerden und das Putting in dem OpenHoldings Methode des Meisters:

let routeConfig = this.router.routes.find(x => x.name === 'holdings'); 
    this.fileInfo = positionInfo; 
    routeConfig.settings = { 
     fileInfo: positionInfo 
    }; 
    this.router.navigateToRoute('holdings'); 

und setzen diese dann in dem Activate-Methode des Kindes:

activate(urlParams, routeMap, navInstr) { 
    this.getPositionData(routeMap.settings.fileInfo); 
} 

Die Einstellungen wurden jedoch nicht beibehalten, nachdem die Navigation ausgeführt wurde.

+0

Offenbar versuchen Sie nur, den Status zwischen den Ansichten zu teilen. Ich injiziere einen State-Store, wenn ich beim Navigieren aus Master-> Detailansichten teilen möchte. Ich bin mir nicht sicher, welche Threads Sie auf Konstruktorinjektion beziehen. Ich verstehe Ihr Szenario oder das der Threads, auf die Sie verweisen, möglicherweise nicht vollständig. –

+0

Im Wesentlichen habe ich gesehen, dass Leute das Eltern-View-Modell in ihrem Kind-View-Model referenzieren, indem sie Konstruktor-Injection benutzen. Dann greift das Kind direkt auf den vom Elternteil benötigten Wert zu. Wenn ich Sie richtig verstehe, registrieren Sie ein separates Objekt mit dem IOC-Container namens "state-store", das Sie sowohl dem Eltern- als auch dem Kind-Objekt hinzufügen? – Bitfiddler

+0

Genau das tue ich. Standardmäßig sind alle injizierten Objekte Singletons, also muss ich nichts anderes tun, als normal injizieren. Und dann benutze set/get-Methoden, um jeden benötigten Zustand zu verarbeiten. –

Verwandte Themen