将数据注入 Durandal 小部件
Injecting data into a Durandal widget
我制作了一个名为 statusAlert
的 "simple" 警报小部件,用于在数据未能按预期到达时显示消息。到目前为止,我无法将数据输入其中。我认为我可以将可观察对象注入小部件,并在可观察对象设置为对象时显示和填充小部件。但我还没有想出如何让这个概念发挥作用。
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>
首先,你的parentdata-binding需要调整一下。应该是这样的:
<div data-bind="widget: {kind: 'statusAlert', ...}"></div>
省略号表示您可能传递给小部件的属性:
<div data-bind="widget: {kind: 'statusAlert', config: {alertObservable: statusAlertObservable}}"></div>
注意 config 属性 是任意的。我可以给它起任何名字。我还可以包括我希望的任何其他自定义属性。
这里有一个微妙之处:在上面的代码中,我传入了 observable 本身,而不是 observable 的值。这意味着在我的小部件的 activate
处理程序中,我需要 de-reference observable 来获取它的值。或者,您可以通过这种方式传递值本身:
<div data-bind="widget: {kind: 'statusAlert', config: {alertObservable: statusAlertObservable()}}"></div>
请注意 statusAlertObservable
上的 parentheses。我不需要 de-reference 在小部件的 viewModel 中观察这个对象,因为它已经 de-referenced 了。
其他一些事情
确保将小部件的视图和 viewModel 放在 widgets 文件夹中包含小部件名称的文件夹下。这是我们的屏幕截图:
在您的情况下,widgets 文件夹下的文件夹名称将是 statusAlert。
其次,确保将小部件的视图模型命名为 viewModel.js
,并将小部件的视图命名为 view.html
。如果不编写自定义 viewLocator
,则不支持其他名称。因此,控制命名约定的是包含文件夹的名称——在本例中为 statusAlert。
第三,将一个名为 activate
的激活处理程序(它必须被称为这个)添加到您的小部件的 viewModel 中,您将 widgetSettings
:
ctor.prototype.activate = function (widgetSettings) {
this.statusAlertObservable = widgetSettings.config.alertObservable;
//alternatively: this.statusAlertObservable = widgetSettings.config.alertObservable();
};
Durandal 在 activate
处理程序上自动将小部件绑定的属性作为 "settings" 传递。
第四,将小部件的构造函数命名为 ctor
并不是一个好主意。这使得调试变得非常困难,尤其是当它们都以这种方式命名时。在您的情况下,将其命名为 StatusAlert
(在 Pascal 的情况下,因为它是一个构造函数)。
最后,看看 Durandal 关于小部件的文档,here。
更新
正如 OP 在他的评论中指出的那样,您可以注册您的小部件绑定,然后简单地将它们与香草绑定 data-bind
。
我不推荐这种方法。 当您有很多小部件绑定时,尤其是在大型应用程序中,很难通过搜索访问它们。此外,其他人很难区分自定义 Knockout 绑定和小部件,因为没有 apparent 差异。在大型代码库中,程序员自己甚至可能开始怀疑哪个是哪个,然后不得不访问他的 main.js 文件或他的自定义 Knockout 绑定来确定哪个是哪个。
至少,如果您坚持要注册您的小部件,至少给它们起以 Widget 结尾的名称。因此,在 OP 的情况下,我们将调用小部件 StatusAlertWidget
.
我制作了一个名为 statusAlert
的 "simple" 警报小部件,用于在数据未能按预期到达时显示消息。到目前为止,我无法将数据输入其中。我认为我可以将可观察对象注入小部件,并在可观察对象设置为对象时显示和填充小部件。但我还没有想出如何让这个概念发挥作用。
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>
首先,你的parentdata-binding需要调整一下。应该是这样的:
<div data-bind="widget: {kind: 'statusAlert', ...}"></div>
省略号表示您可能传递给小部件的属性:
<div data-bind="widget: {kind: 'statusAlert', config: {alertObservable: statusAlertObservable}}"></div>
注意 config 属性 是任意的。我可以给它起任何名字。我还可以包括我希望的任何其他自定义属性。
这里有一个微妙之处:在上面的代码中,我传入了 observable 本身,而不是 observable 的值。这意味着在我的小部件的 activate
处理程序中,我需要 de-reference observable 来获取它的值。或者,您可以通过这种方式传递值本身:
<div data-bind="widget: {kind: 'statusAlert', config: {alertObservable: statusAlertObservable()}}"></div>
请注意 statusAlertObservable
上的 parentheses。我不需要 de-reference 在小部件的 viewModel 中观察这个对象,因为它已经 de-referenced 了。
其他一些事情
确保将小部件的视图和 viewModel 放在 widgets 文件夹中包含小部件名称的文件夹下。这是我们的屏幕截图:
在您的情况下,widgets 文件夹下的文件夹名称将是 statusAlert。
其次,确保将小部件的视图模型命名为 viewModel.js
,并将小部件的视图命名为 view.html
。如果不编写自定义 viewLocator
,则不支持其他名称。因此,控制命名约定的是包含文件夹的名称——在本例中为 statusAlert。
第三,将一个名为 activate
的激活处理程序(它必须被称为这个)添加到您的小部件的 viewModel 中,您将 widgetSettings
:
ctor.prototype.activate = function (widgetSettings) {
this.statusAlertObservable = widgetSettings.config.alertObservable;
//alternatively: this.statusAlertObservable = widgetSettings.config.alertObservable();
};
Durandal 在 activate
处理程序上自动将小部件绑定的属性作为 "settings" 传递。
第四,将小部件的构造函数命名为 ctor
并不是一个好主意。这使得调试变得非常困难,尤其是当它们都以这种方式命名时。在您的情况下,将其命名为 StatusAlert
(在 Pascal 的情况下,因为它是一个构造函数)。
最后,看看 Durandal 关于小部件的文档,here。
更新
正如 OP 在他的评论中指出的那样,您可以注册您的小部件绑定,然后简单地将它们与香草绑定 data-bind
。
我不推荐这种方法。 当您有很多小部件绑定时,尤其是在大型应用程序中,很难通过搜索访问它们。此外,其他人很难区分自定义 Knockout 绑定和小部件,因为没有 apparent 差异。在大型代码库中,程序员自己甚至可能开始怀疑哪个是哪个,然后不得不访问他的 main.js 文件或他的自定义 Knockout 绑定来确定哪个是哪个。
至少,如果您坚持要注册您的小部件,至少给它们起以 Widget 结尾的名称。因此,在 OP 的情况下,我们将调用小部件 StatusAlertWidget
.