将数据注入Durandal小部件

时间:2015-01-28 21:08:10

标签: widget durandal

我创建了一个名为statusAlert的“简单”警报窗口小部件,用于在数据无法按预期到达时显示消息。到目前为止,我无法将数据输入其中。我想我可以在窗口小部件中注入一个observable,并在observable设置为一个对象时显示并填充窗口小部件。但我还没弄清楚如何使这个概念有效。

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>

1 个答案:

答案 0 :(得分:1)

首先,需要调整父数据绑定。它应该如下:

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

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

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

请注意, config 属性是任意的。我可以把它命名为任何东西。我还可以包括我希望的任何其他自定义属性。

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

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

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

其他几件事

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

widget folder structure

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

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

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

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

Durandal会自动将您的小工具绑定属性传递为&#34;设置&#34;在activate处理程序上。

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

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

<强>更新

正如OP在他的评论中指出的那样,你可以注册你的小部件绑定,然后简单地用一个香草data-bind绑定它们。

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

至少,如果你坚持注册你的小部件,至少要给它们命名,例如Widget。因此,在OP的情况下,我们会调用小部件StatusAlertWidget