【问题标题】:Pass data to not-yet-loaded view in Aurelia将数据传递到 Aurelia 中尚未加载的视图
【发布时间】:2017-02-17 09:53:50
【问题描述】:

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

我正在尝试使用事件聚合器,但是由于事物的生命周期,我在第一次导航时总是得到一个空白的详细信息屏幕。当我第一次导航到“图书详细信息”视图时,在出版商(畅销书)发送消息之前,还没有订阅 ViewDetailsMessage。由于我将视图模型设置为单例,因此后续点击工作正常(因为详细信息视图已经构建并订阅了事件)。

如何解决 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!"
        });
    }
}

我需要在孩子的激活方法中添加一些逻辑,以确保我请求正确的父母持有文件。

【问题讨论】:

  • 我们需要看一些代码,看看你是怎么做的,看看我们能提供什么帮助。
  • @KellyEthridge 我添加了一些代码进行比较。

标签: aurelia


【解决方案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 的单个实例,从而可以轻松共享状态。

【讨论】:

    【解决方案2】:

    我目前的解决方案,虽然没有我想要的那么漂亮,但如下:

    源视图 (bestSellersView) 是一个单例并订阅“GetCurrentBookMes​​sage”。当用户选择一本书时,Source 将其保存在本地并导航到“BookDetailsView”。 BookDetailsView 被构造,订阅一个“SetCurrentBookMes​​sage”,当被激活时,它发送一个GetCurrentBookMes​​sage。源视图以“SetCurrentBookMes​​sage”回答。

    这会因多个来源而变得混乱,我必须有一些方法来解决导航的来源以选择“正确”来源,但对于今天来说这是可行的。

    编辑 01 我还尝试摆脱所有事件聚合器的东西并将其放入主控的 OpenHoldings 方法中:

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

    然后把这个放到孩子的activate方法中:

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

    但导航执行后设置并没有保留。

    【讨论】:

    • 看起来您只是想在视图之间共享状态。在从主视图导航时需要共享时,我会注入一个状态存储 - > 详细视图。我不确定您指的是关于构造函数注入的线程。我可能不完全理解您的情况或您引用的线程的情况。
    • 基本上我已经看到建议人们通过使用构造函数注入在他们的子视图模型中引用父视图模型。然后子级直接访问父级所需的值。如果我对您的理解正确,您是否在 IOC 容器中注册了一个名为“state-store”的单独对象,您将其注入到父级和子级中?
    • 这正是我所做的。默认情况下,所有注入的对象都是单例,所以除了正常注入之外我不需要做任何事情。然后只需使用 set/get 方法来处理我需要的任何状态。
    • @KellyEthridge 我想我喜欢状态存储的方法。它大大简化了我的逻辑,而且我不必搞乱订阅。谢谢!
    • @KellyEthridge 刚刚实现了 StateStore,简直太美了。简单,容易,而且效果很好。如果您正在收集统计数据,只需发布​​一条答案:StateStore see other cmets... 我很乐意给予信任。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-16
    • 2015-11-18
    相关资源
    最近更新 更多