【发布时间】:2017-09-24 10:55:42
【问题描述】:
是否存在与 Promises 一起使用的良好绑定实现?我尝试的一切似乎最终都会给我一个错误,即无法将绑定多次应用于同一个元素(我理解,并试图找到解决方法)。我找到了this,但它相当陈旧,而且似乎只适用于不控制后代绑定的绑定。
我也尝试编写自己的实现来尝试删除子级,并且仅在承诺解决后重新附加/绑定它们,但得到了相同的结果。
作为替代方案,我可以创建一个异步计算的 observable 来绑定,但随后键入(我正在使用 TypeScript)变得有点模糊,因为我会返回一个 promise,但是从 observable 读取的值会是别的东西。我可以(有效地)将其键入为“Promise | T”,但这可能会令人困惑,因为它实际上只会是“T”。
编辑:这是我正在谈论的打字问题。请记住,我正在使用一种方法将 observables 隐藏在 getter/setter 后面,以便我的属性看起来像常规的 javascript 属性。我的想法是使用装饰器将返回承诺的 getter 转换为返回值的 getter
export class Foo {
@promise get bar(): int {
return new Promise<int>((resolve, reject) => {
setTimeout(() => { resolve(1) }, 100);
});
}
}
这样做看起来没问题,只是 TypeScript 会抱怨返回类型。我可以将它投射到任何地方,但这就是不对的。或者,我可以将 getter 返回值转换为 Promise | T,但它歪曲了实际的返回类型,因为它总是 T。
在绑定的方式上,我不希望重新绑定所有内容,但在“if”绑定(这实际上是我正在尝试使用的)之类的情况下,似乎没有办法解决它。
编辑 2:以防万一,这是我当前的“承诺”绑定处理程序化身:
import * as ko from "knockout";
ko.bindingHandlers["promise"] = {
init(element: HTMLElement, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
let first = true;
function apply(bindingName: string, val: any) {
ko.applyBindingsToNode(element, { [bindingName]: val }, bindingContext);
}
ko.computed(() => {
let bindings = ko.unwrap(valueAccessor());
if(bindings) {
ko.tasks.schedule(() => {
for(let bindingName in bindings) {
let promise = bindings[bindingName] as Promise<any>;
if(promise && promise.then) {
promise.then(val => {
apply(bindingName, val);
first = false;
});
} else {
apply(bindingName, bindings[bindingName]);
first = false;
}
}
});
}
}, null, { disposeWhenNodeIsRemoved: element })();
return {
controlsDescendantBindings: false
};
}
}
ko.virtualElements.allowedBindings["promise"] = true;
我尝试将“controlsDescendantBindings”设置为 false,这适用于某些情况,但在嵌套 promise 绑定时似乎会造成一些破坏。
编辑 3:至于我想要做的事情,大致上是这样的(注意:使用 Bootstrap)。
<ul class="nav navbar-nav">
<!-- ko promise: { if: canAccessFooBar } -->
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown">Foobar</a>
<ul class="dropdown-menu>
<!-- ko promise: { if: canAccessFoo } -->
<li>
<a href="/foo">Foo</a>
</li>
<!-- /ko -->
<!-- ko promise: { if: canAccessBar } -->
<li>
<a href="/bar">Bar</a>
</li>
<!-- /ko -->
</ul>
</li>
<!-- /ko -->
</ul>
canAccessFoo、canAccessBar 和 canAccessFooBar 是解析为布尔值的 Promise。
【问题讨论】:
-
为什么要多次应用绑定?您可以异步更新现有的 observables,只要您预先创建它们并且不要用新实例替换它们。
-
事后更新 observables 是我列出的一个选项,但这带来了打字问题,可能会给后来进来的人造成混淆。
-
你想要完成什么?
-
使用 observable 来保存你的视图模型是可以的。查看stackoverflow.com/a/27453338/1287183 或stackoverflow.com/a/12316626/1287183
-
我不太了解您提到的打字问题。为什么它必须返回一个 promise 而不是简单地更新强类型的 observables?你能发布一些示例代码吗?
标签: typescript knockout.js data-binding promise