复合控件的自定义敲除绑定
Custom Knockout binding for Compound Control
我正在寻找一个自定义绑定的示例(如果可能的话,jsfiddle),用于我们多年前称为“复合组件”的东西。我真的不希望有人为我编写代码。在我投入大量时间之前,我只想查看一些样本,但我找不到任何样本。大多数自定义绑定示例只是一种方式。只是询问您是否知道类似的样本……
大部分 HTML/CSS 都是设计团队给我的,所以布局并不总是我的选择。在这种情况下,日期、phone 数字和社会保障输入都是使用共同的“主题”创建的。该主题是在 div 中包含三个独立的元素。例如,日期有一个代表月,一个代表日,一个代表年。 (我认为我们不需要因为他们是纺纱厂而使这件事复杂化)。需要验证和 max/min 输入限制。
我创建了一个对象如下
var SplitDate = function (date) {
var self = this;
self.month = ko.observable();
self.day = ko.observable();
self.year = ko.observable();
var momentDate = moment(date);
if (momentDate.isValid()) {
self.month(momentDate.month() + 1);
self.day(momentDate.day());
self.year(momentDate.year());
}
}
在我的视图模型中,我都试过了
self.dateOfBirth = new SplitDate(myDate);
和
self.dateOfBirth = ko.observable(new SplitDate(myDate));
但是这些都没有使用标准值绑定正确绑定,例如
data-binding = "value: dateOfBirth.day" or data-binding = "value: dateOfBirth().day"
所以我假设我需要自定义绑定。我不确定最好的方法是什么,以及是否所有这些都需要是可观察的。我们正在使用 Knockout 验证,所以我也希望我会为 isValid() 添加一个函数到 SplitDate。
所以我的问题是,在我花几个小时摸索这个之前,有没有人有一个很好的例子?
您的 SplitDate
对象将月、日和年作为单独的组成部分进行跟踪。在我看来,您似乎在尝试使用完整日期来设置它们,但遇到了麻烦。我怀疑你正在做这样的事情:
self.dateOfBirth = new SplitDate(newDate);
这行不通,您的视图已绑定到之前 SplitDate
中的可观察对象。您需要做的是更新日期组件。
但是,我认为您的做法是错误的。拆分日期应该是一个完整日期的包装,而不仅仅是一些日期组件。您只需要为要支持的不同字段提供访问器。简而言之,您需要一个完整日期的可观察值,然后计算不同字段的可观察值。
function SplitDate(date) {
var _date = ko.observable(); // the backing field
setDate(date);
// we can intercept set attempts to validate
this.date = ko.computed({ read: _date, write: setDate });
this.year = ko.computed({ read: makeGetter('year'), write: makeSetter('year') });
// we need to special case months to offset to be 1-based
this.month = ko.computed({ read: getMonth, write: setMonth });
// the date is the day of the month, day is day of the week
this.day = ko.computed({ read: makeGetter('date'), write: makeSetter('date') });
function setDate(date) {
var momentDate = moment(date);
if (momentDate.isValid()) _date(momentDate);
}
function makeGetter(field) {
var getter = moment.fn[field];
return function () {
var date = _date();
if (date) return getter.call(date);
};
}
function makeSetter(field) {
var setter = moment.fn[field];
return function (value) {
var date = _date();
if (date) {
setter.call(date, value);
// we modified the underlying value, notify
_date.valueHasMutated();
}
};
}
// we need to offset months
function getMonth() { // 1-12
var date = _date();
if (date) return date.month() + 1;
}
function setMonth(month) { // 1-12
var date = _date();
if (date) {
date.month(month - 1);
_date.valueHasMutated();
}
}
}
有了这个,更改日期的任何组件的值,就好像它们是常规可观察值一样。
self.dateOfBirth = new SplitDate(date);
self.dateOfBirth.month(8); // August
self.dateOfBirth.date(newDate);
您应该能够单独绑定到字段,并且字段上的任何更新都会如您所料更新基础日期。
<input type="text" data-bind="value: dateOfBirth.date"/>
<input type="text" data-bind="value: dateOfBirth.year"/>
<input type="text" data-bind="value: dateOfBirth.month"/>
<input type="text" data-bind="value: dateOfBirth.day"/>
我正在寻找一个自定义绑定的示例(如果可能的话,jsfiddle),用于我们多年前称为“复合组件”的东西。我真的不希望有人为我编写代码。在我投入大量时间之前,我只想查看一些样本,但我找不到任何样本。大多数自定义绑定示例只是一种方式。只是询问您是否知道类似的样本……
大部分 HTML/CSS 都是设计团队给我的,所以布局并不总是我的选择。在这种情况下,日期、phone 数字和社会保障输入都是使用共同的“主题”创建的。该主题是在 div 中包含三个独立的元素。例如,日期有一个代表月,一个代表日,一个代表年。 (我认为我们不需要因为他们是纺纱厂而使这件事复杂化)。需要验证和 max/min 输入限制。
我创建了一个对象如下
var SplitDate = function (date) {
var self = this;
self.month = ko.observable();
self.day = ko.observable();
self.year = ko.observable();
var momentDate = moment(date);
if (momentDate.isValid()) {
self.month(momentDate.month() + 1);
self.day(momentDate.day());
self.year(momentDate.year());
}
}
在我的视图模型中,我都试过了
self.dateOfBirth = new SplitDate(myDate);
和
self.dateOfBirth = ko.observable(new SplitDate(myDate));
但是这些都没有使用标准值绑定正确绑定,例如
data-binding = "value: dateOfBirth.day" or data-binding = "value: dateOfBirth().day"
所以我假设我需要自定义绑定。我不确定最好的方法是什么,以及是否所有这些都需要是可观察的。我们正在使用 Knockout 验证,所以我也希望我会为 isValid() 添加一个函数到 SplitDate。
所以我的问题是,在我花几个小时摸索这个之前,有没有人有一个很好的例子?
您的 SplitDate
对象将月、日和年作为单独的组成部分进行跟踪。在我看来,您似乎在尝试使用完整日期来设置它们,但遇到了麻烦。我怀疑你正在做这样的事情:
self.dateOfBirth = new SplitDate(newDate);
这行不通,您的视图已绑定到之前 SplitDate
中的可观察对象。您需要做的是更新日期组件。
但是,我认为您的做法是错误的。拆分日期应该是一个完整日期的包装,而不仅仅是一些日期组件。您只需要为要支持的不同字段提供访问器。简而言之,您需要一个完整日期的可观察值,然后计算不同字段的可观察值。
function SplitDate(date) {
var _date = ko.observable(); // the backing field
setDate(date);
// we can intercept set attempts to validate
this.date = ko.computed({ read: _date, write: setDate });
this.year = ko.computed({ read: makeGetter('year'), write: makeSetter('year') });
// we need to special case months to offset to be 1-based
this.month = ko.computed({ read: getMonth, write: setMonth });
// the date is the day of the month, day is day of the week
this.day = ko.computed({ read: makeGetter('date'), write: makeSetter('date') });
function setDate(date) {
var momentDate = moment(date);
if (momentDate.isValid()) _date(momentDate);
}
function makeGetter(field) {
var getter = moment.fn[field];
return function () {
var date = _date();
if (date) return getter.call(date);
};
}
function makeSetter(field) {
var setter = moment.fn[field];
return function (value) {
var date = _date();
if (date) {
setter.call(date, value);
// we modified the underlying value, notify
_date.valueHasMutated();
}
};
}
// we need to offset months
function getMonth() { // 1-12
var date = _date();
if (date) return date.month() + 1;
}
function setMonth(month) { // 1-12
var date = _date();
if (date) {
date.month(month - 1);
_date.valueHasMutated();
}
}
}
有了这个,更改日期的任何组件的值,就好像它们是常规可观察值一样。
self.dateOfBirth = new SplitDate(date);
self.dateOfBirth.month(8); // August
self.dateOfBirth.date(newDate);
您应该能够单独绑定到字段,并且字段上的任何更新都会如您所料更新基础日期。
<input type="text" data-bind="value: dateOfBirth.date"/>
<input type="text" data-bind="value: dateOfBirth.year"/>
<input type="text" data-bind="value: dateOfBirth.month"/>
<input type="text" data-bind="value: dateOfBirth.day"/>