【问题标题】:Injecting data into a Durandal widget将数据注入 Durandal 小部件
【发布时间】:2015-01-30 03:41:04
【问题描述】:

我制作了一个名为statusAlert 的“简单”警报小部件,用于在数据未能按预期到达时显示消息。到目前为止,我无法将数据输入其中。我认为我可以将一个可观察对象注入到小部件中,并在可观察对象设置为对象时显示和填充小部件。但我还没有弄清楚如何让这个概念发挥作用。

statusAlert/view.html

<div class="alert alert-danger" role="alert" data-bind="visible: content">
    <button type="button" class="close" aria-label="Close" data-bind="click: hide"><span aria-hidden="true"><i class="fa fa-times"></i></span></button>
    <button type="button" class="close" aria-label="Show Details" data-bind="click: showDetails"><span aria-hidden="true"><i class="fa fa-info-circle"></i></span></button>
    <p class="lead" data-bind="text: header"></p>
    <p data-bind="text: message"></p>
    <p data-bind="visible: detailsIsVisible"><pre data-bind="text: details"></pre></p>
</div>

statusAlert/viewmodel.js

define(['knockout'], function (ko) {

    var ctor = function () {
        this.content = ko.observable();
        this.detailsIsVisible = ko.observable(false);
    };

    // Methods.

    // Activate event handler.
    ctor.prototype.activate = function () {
       //TODO What goes here?
    };

    // Destroying the content will result in the alert becoming invisible.
    ctor.prototype.hide = function () {
        this.content(null);
    };

    ctor.prototype.showDetails = function () {
        this.detailsIsVisible(true);
    };

    // Data fields: Computed observables that extract data from 'content.'

    ctor.prototype.header = ko.computed(function () {
        if (this.content) {
            return this.content() ? this.content().header : null;
        }
        return null;
    }, this);

    ctor.prototype.message = ko.computed(function () {
        if (this.content) {
            return this.content() ? this.content().message : null;
        }
        return null;
    }, this);

    ctor.prototype.details = ko.computed(function () {
        if (this.content) {
            return this.content() ? this.content().details : null;
        }
        return null;
    }, this); 

    return ctor;
});

父视图模型的相关代码

var statusAlertObservable = ko.observable();

$.ajax({
    success: function (data, status, request) {
        if (data.ResponseStatus.ErrorCode) {
            statusAlertObservable({
                header: "Service reports error.",
                message: data.ResponseStatus.Message,
                details: data.ResponseStatus
            });
        } else {
        // (do something with data)
        }
    },
    error: function (data, status, error) {
        statusAlertObservable({
            header: "Error getting application data.",
            message: error,
            details: data
        });
    }
});

return {
    statusAlertObservable: statusAlertObservable,
    //...
}

父视图的相关代码

<div data-bind="statusAlert: 0"></div>

【问题讨论】:

    标签: widget durandal


    【解决方案1】:

    首先,需要调整您的父数据绑定。应该是这样的:

    <div data-bind="widget: {kind: 'statusAlert', ...}"></div>
    

    省略号表示您可能传递给小部件的属性:

    <div data-bind="widget: {kind: 'statusAlert', config: {alertObservable: statusAlertObservable}}"></div>
    

    请注意,config 属性是任意的。我可以给它起任何名字。我还可以包含我希望的任何其他自定义属性。

    这里有一个微妙之处:在上面的代码中,我传入的是 observable 本身,而不是 observable 的值。这意味着在我的小部件的 activate 处理程序中,我需要取消引用 observable 以获得它的值。或者,您可以通过这种方式传递值本身:

    <div data-bind="widget: {kind: 'statusAlert', config: {alertObservable: statusAlertObservable()}}"></div>
    

    注意statusAlertObservable 上的括号。我不需要在小部件的 viewModel 中取消引用这个 observable,因为它已经被取消引用了。

    其他一些事情

    确保将小部件的视图和 viewModel 放在带有小部件名称的小部件文件夹中的文件夹下。这是我们的截图:

    在您的情况下,小部件文件夹下的文件夹名称将是 statusAlert

    其次,确保将小部件的 viewModel 命名为 viewModel.js,并将小部件的视图命名为 view.html。如果不编写自定义 viewLocator,则不支持其他名称。因此,控制命名约定的是包含文件夹的名称(在本例中为 statusAlert)。

    第三,将一个名为activate(必须称为this)的激活处理程序添加到您的小部件的viewModel中,并在其中传递您的widgetSettings

    ctor.prototype.activate = function (widgetSettings) {
        this.statusAlertObservable = widgetSettings.config.alertObservable;
        //alternatively: this.statusAlertObservable = widgetSettings.config.alertObservable();
    };
    

    Durandal 自动将小部件绑定的属性作为“设置”传递给 activate 处理程序。

    第四,将小部件的构造函数命名为ctor 不是一个好主意。这使得调试非常困难,特别是如果它们都以这种方式命名。在您的情况下,将其命名为 StatusAlert(在 Pascal 情况下,因为它是一个构造函数)。

    最后,看看 Durandal 关于小部件的文档,here

    更新

    正如 OP 在他的 cmets 中指出的那样,您可以注册您的小部件绑定,然后简单地使用原版 data-bind 绑定它们。

    我不推荐这种方法。当您有很多小部件绑定时,特别是在大型应用程序中,很难通过搜索访问它们。此外,其他人很难区分自定义 Knockout 绑定和小部件,因为没有明显的区别。在大型代码库中,程序员自己甚至可能开始怀疑哪个是哪个,然后必须访问他的 main.js 文件或他的自定义 Knockout 绑定来确定哪个是哪个。

    至少,如果您坚持注册您的小部件,至少要给它们起以 Widget 结尾的名称。因此,在 OP 的情况下,我们将调用小部件 StatusAlertWidget

    【讨论】:

    • 您引用的 Durandal 文档指出您可以注册小部件种类(我没有在我的代码中显示),然后您可以像我一样编写数据绑定。请参阅“使用小部件”部分。
    • @JayBienvenu 是的,没错,但由于您没有显示代码的那部分,我的回答没有反映这种方法。不过,这并不会使答案的其余部分无效。您对其余答案有意见吗?
    • 我没有进一步的评论。
    猜你喜欢
    • 2015-01-26
    • 1970-01-01
    • 2013-09-23
    • 2013-12-17
    • 1970-01-01
    • 1970-01-01
    • 2014-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多