我正在将项目转换为Typescript,它使用了Kendo UI的MVVM架构。但是我对类的概念及其与视图模型的关系存在一些问题。
我将建立一个类并扩展kendo.data.ObservableObject
,这是您创建视图模型的方法,并使用我的字段填充它,如下所示。
export class ViewModelSample extends kendo.data.ObservableObject {
Id: string = null;
Name: string = null;
Items: kendo.data.ObservableArray = [];
// other fields
constructor() {
super();
}
map(params){
// some code
}
}
基本上这个类代表我的视图模型,很好地封装了。所以我这样召唤它;
var viewModel = new ViewModelSample();
kendo.bind($('#binding-area'), viewModel);
这种方法效果很好,但行为变得有点尴尬。例如,如果我在类中有一个集合并向其推送内容,则用户界面不会更新。
如果我在普通的javascript中这样做,它可以工作;
viewModel.Items.push(new Item(/* parameters */));
// view model updates, and user interface updates
但是,如果我在打字稿中执行此操作,则视图模型会更新,但DOM不会。我必须手动输入...
viewModel.Items.trigger('change');
为了让UI更新。
任何人都可以帮助我理解为什么会这样吗?
答案 0 :(得分:4)
我也遇到过这个问题,实际上是由于TypeScript生成JS的方式。
在普通的JS中,您可以这样做:
new kendo.ObservableObject({
items: []
});
并且构造函数会自动将items[]
包装到新的ObservableArray
中。
然而,TypeScript中的行为失败,因为代码:
export class ViewModelSample extends kendo.data.ObservableObject {
Items: kendo.data.ObservableArray = [];
constructor() {
super();
}
实际上会生成类似的内容:
function ViewModelSample() { // constructor
_super.call(this); // call to ObservableObject constructor (super())
this.Items = []; // add Items to this.
}
因此,Items
属性在调用ObservableObject
构造函数之后才会添加到ViewModel中,因此Kendo不会知道它,也不会将其包装到{{1 }}
排序只是从剑道期望的普通JavaScript开始的。
@ Anzeo关于手动将项目初始化为ObservableArray
的建议将主要起作用
ObservableArray
然而,ObservableArray的Items: kendo.data.ObservableArray = new kendo.data.ObservableArray([]);
将无法正确设置为ViewModel,因此有时如果您尝试将MVM绑定到绑定到parent
的ListView模板内的ViewModel上的函数或属性,它将无法在ViewModel上找到属性或函数。
您可以通过在devtools控制台中执行此操作来证明:
Items
这确实是一种情况,在这种情况下,TypeScript只会阻碍它... ...
正确的解决方案是在调用x = new kendo.data.ObservableObject({
items: []
});
x.items.parent(); // returns the object 'x' (correct)
y = new kendo.data.ObservableObject();
y.items = new kendo.data.ObservableArray([]);
y.items.parent(); // return undefined (but should be the object 'y')
之前,在构造函数中初始分配类变量。
super()
以正确的顺序生成JS:
class ViewModelSample extends ObservableObject {
Items: kendo.data.ObservableArray;
constructor() {
this.Items = [];
super();
}
}
有趣的是,typescriptlang.org上的游乐场似乎并不关心这一行:
function ViewModelSample() {
this.Items = []; // Items assigned before call to ObservableObject constructor
_super.call(this);
}
将一个数组赋给一个应该是this.Items = [];
类型的变量,但如果真正的编译器抛出错误,那么你也可以这样做
ObservableArray
这应该有效。只要生成的JS在调用this.Items = new kendo.data.ObservableArray([]);
构造函数之前将Items
属性添加到对象。
答案 1 :(得分:3)
您必须在构造函数的末尾调用super.init(this)
来正确设置依赖关系跟踪。根据文件:
constructor() {
...
super();
super.init(this);
}
答案 2 :(得分:2)
您需要将items
属性实例化为Kendo ObservableArray。目前你只是在TypeScript中定义它的类型(我很惊讶编译器没有抱怨这个?)。
将您的代码更新为:
Items: kendo.data.ObservableArray = new kendo.data.ObservableArray([]);
有关详细信息,请参阅Kendo docs。