我使用 knockout.js 来绑定(bind)要查看的值。 当显示模式时,我初始化格式化程序。这是示例:
<input type="text" id="propertyName" class="form-control" name="name" required="" data-bind="value: Name">
$("#exampleFormModal").on("shown.bs.modal", function () {
self.InitFormatter();
});
self.InitFormatter = function () {
$('#propertyName').formatter({
'pattern': '{{aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}}',
'persistent': true
});
}
问题是value:Name
中有空值
最佳答案
将 knockout 与执行任何类型 DOM 操作的库一起使用 - 包括元素上的值更新 - 需要 custom binding handler ,这样 knockout 就可以 a) 正确初始化该库,b) 在 View 模型和 View 之间传递任何更新。
为 formatter.js 编写自定义绑定(bind)处理程序很棘手,因为 formatter.js 对输入元素上发生的所有与值相关的事件(键盘、粘贴)进行非常严格的控制 - 而不暴露其自己的任何事件。
换句话来说,设置很容易,但是当值发生变化时很难得到通知。但这正是保持 View 模型最新所必需的。
为了能够做到这一点,我们必须连接格式化程序的内部函数之一 - _processKey
method 。只要输入的值发生变化,就会调用此方法,因此它是设置一个小“告密者”的最佳位置,可以在值发生变化时通知 knockout 。
免责声明这是一个黑客行为。只要 formatter.js 内部发生变化,它就会中断。然而,在当前版本 0.1.5 中,它似乎运行得相当好。
这样我们就可以像这样绑定(bind)我们的 View :
<input data-bind="formatter: {
value: someObservable,
pattern: '{{9999}}-{{9999}},
persistent: true
}">
当 someObservable
发生变化时,knockout 可以填充输入值,并且由于 Hook 到 _processKey
,它还可以在每当 someObservable
发生变化时更新 someObservable
输入值发生变化。
绑定(bind)处理程序的完整实现如下(它没有 jQuery 依赖项):
// ko-formatter.js
/* global ko, Formatter */
ko.bindingHandlers.formatter = {
init: function (element, valueAccessor) {
var options = ko.unwrap(valueAccessor()) || {},
instance = new Formatter(element, ko.toJS(options)),
_processKey = Formatter.prototype._processKey,
valueSubs, patternSubs, patternsSubs;
if (ko.isWritableObservable(options.value)) {
// capture initial element value
options.value(element.value);
// shadow the internal _processKey method so we see value changes
instance._processKey = function () {
_processKey.apply(this, arguments);
options.value(element.value);
};
// catch the 'cut' event that formatter.js originally ignores
ko.utils.registerEventHandler(element, 'input', function () {
options.value(element.value);
});
// subscribe to options.value to achieve two-way binding
valueSubs = options.value.subscribe(function (newValue) {
// back out if observable and element values are equal
if (newValue === element.value) return;
// otherwise reset element and "type in" new observable value
element.value = '';
_processKey.call(instance, newValue, false, true);
// write formatted value back into observable
if (element.value !== newValue) options.value(element.value);
});
}
// support updating "pattern" option through knockout
if (ko.isObservable(options.pattern)) {
patternSubs = options.pattern.subscribe(function (newPattern) {
instance.resetPattern(newPattern);
});
}
// support updating "patterns" option through knockout
if (ko.isObservable(options.patterns)) {
patternsSubs = options.patterns.subscribe(function (newPatterns) {
instance.opts.patterns = newPatterns;
instance.resetPattern();
});
}
// clean up after ourselves
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
if (valueSubs) valueSubs.dispose();
if (patternSubs) patternSubs.dispose();
if (patternsSubs) patternsSubs.dispose();
});
}
// this binding has no "update" part, it's not necessary
};
这还支持使模式
可观察,因此您可以动态更改输入字段的模式。
现场演示(展开以运行):
// ko-formatter.js
/* global ko, Formatter */
ko.bindingHandlers.formatter = {
init: function (element, valueAccessor) {
var options = ko.unwrap(valueAccessor()) || {},
instance = new Formatter(element, ko.toJS(options)),
_processKey = Formatter.prototype._processKey,
valueSubs, patternSubs, patternsSubs;
if (ko.isWritableObservable(options.value)) {
// capture initial element value
options.value(element.value);
// shadow the internal _processKey method so we see value changes
instance._processKey = function () {
_processKey.apply(this, arguments);
options.value(element.value);
};
// catch the 'cut' event that formatter.js originally ignores
ko.utils.registerEventHandler(element, 'input', function () {
options.value(element.value);
});
// subscribe to options.value to achieve two-way binding
valueSubs = options.value.subscribe(function (newValue) {
// back out if observable and element values are equal
if (newValue === element.value) return;
// otherwise reset element and "type" new observable value
element.value = '';
_processKey.call(instance, newValue, false, true);
// write formatted value back into observable
if (element.value !== newValue) options.value(element.value);
});
}
// support updating "pattern" option through knockout
if (ko.isObservable(options.pattern)) {
patternSubs = options.pattern.subscribe(function (newPattern) {
instance.resetPattern(newPattern);
});
}
// support updating "patterns" option through knockout
if (ko.isObservable(options.patterns)) {
patternsSubs = options.patterns.subscribe(function (newPatterns) {
instance.opts.patterns = newPatterns;
instance.resetPattern();
});
}
// clean up after ourselves
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
if (valueSubs) valueSubs.dispose();
if (patternSubs) patternSubs.dispose();
if (patternsSubs) patternsSubs.dispose();
});
}
// this binding has no "update" part, it's not necessary
};
// viewmodel implementation
ko.applyBindings({
inputPattern: ko.observable('{{9999}}-{{9999}}-{{9999}}-{{9999}}'),
inputValue: ko.observable(),
setValidValue: function () {
var dummy = this.inputPattern().replace(/\{\{([a9*]+)\}\}/g, function ($0, $1) {
return $1.replace(/\*/g, "x");
});
this.inputValue(dummy);
},
setInvalidValue: function () {
this.inputValue('invalid value');
}
});
input {
width: 20em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/formatter.js/0.1.5/formatter.min.js"></script>
View:<br>
<input data-bind="formatter: {
value: inputValue,
pattern: inputPattern,
persistent: true
}">
<input data-bind="value: inputPattern"><br>
<button data-bind="click: setValidValue">Set valid value</button>
<button data-bind="click: setInvalidValue">Set invalid value</button>
<hr>
Viewmodel:<br>
<pre data-bind="text: ko.toJSON($root, null ,2)"></pre>
关于javascript - formatter.js 覆盖 knockout 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39139555/