将数据传递到Aurelia中尚未加载的视图

时间:2017-02-16 19:35:46

标签: aurelia

我从一个视图(称为bestSellersView)导航到另一个视图(BookDetailsView)。有多种不同的父母'可以导航到“预订详细信息”的视图。他们都需要将要观看的书传递到下一个视图。我不想像某些线程所建议的那样将源视图注入到详细信息视图中,因为我的构造函数会随着每个使用详细信息子视图的新视图而增长。

我正在尝试使用事件聚合器,但由于事物的生命周期,我在第一次导航时总是得到一个空白的详细信息屏幕。当我第一次导航到书的详细信息时,查看ViewDetailsMessage尚未在发布者(畅销书)发送消息之前订阅。由于我将viewmodel设置为singleton,后续点击工作正常(因为详细信息视图已经构建并订阅了事件)。

如何解决Aurelia的鸡蛋问题?

修改01

以下是我遇到问题时的所作所为:

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!"
        });
    }
}

以下是我现在正在做的事情:

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!"
        });
    }
}

我需要为孩子的激活方法添加一些逻辑,以确保我要求正确的父母馆藏文件。

2 个答案:

答案 0 :(得分:1)

我目前的解决方案虽然不如我所希望的那样漂亮但如下:

源视图(bestSellersView)是一个单例并订阅" GetCurrentBookMes​​sage"。当用户选择一本书时,Source会在本地保存它并导航到" BookDetailsView"。构建BookDetailsView,订阅" SetCurrentBookMes​​sage"并且,在激活时,它会发送GetCurrentBookMes​​sage。源视图以" SetCurrentBookMes​​sage"。

回答

这将使多个来源变得混乱,我将不得不通过某种方式来解决导航来自哪里以选择“正确”的来源。来源,但今天这是有效的。

修改01 我还试图摆脱所有事件聚合器的东西,并把它放在master的OpenHoldings方法中:

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

然后将其放入孩子的激活方法中:

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

但导航执行后设置并未持续。

答案 1 :(得分:1)

听起来你需要在视图之间共享状态。我使用StateStore类注入到任何希望共享状态的视图中。默认情况下,所有注入的对象都是 Singletons ,这样可以轻松共享状态。一个非常简单的例子可能是(在TypeScript中):

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

这将在视图之间共享一个StateStore实例,以便轻松共享状态。