我一直在使用TypeScript和KnockoutJS创建一个htmlHelper函数来编辑电子邮件列表。
电子邮件列表是名为电子邮件的Knockout ObservableArray,我有一个针对每个项目的链接以删除它们。这是HTML片段:
<ul data-bind="foreach: emails" >
<li>
<a href="#" data-bind="click: $parent.deleteItem">Delete</a>
<span data-bind="text: $data"></span>
</li>
</ul>
删除链接绑定到 $ parent.deleteItem 这是viewmodel中的方法:
// remove item
public deleteItem(emailToDelete: string) {
// remove item from list
this.emails.remove(emailToDelete);
}
这一切都有效,直到执行deleteItem方法。调用此方法时的“this”是数组中的项,而不是视图模型。因此this.emails是一个空引用并失败。
我知道TypeScript支持Lambda语法但我找不到正确的写法(那里有几个例子)。
或者我可以采取不同的方法吗?
答案 0 :(得分:48)
通过在类构造函数
中声明方法体,可以正确关闭'this'class VM {
public deleteItem: (emailToDelete: string) => void;
constructor() {
this.deleteItem = (emailToDelete: string) => {
// 'this' will be pointing to 'this' from constructor
// no matter from where this method will be called
this.emails.remove(emailToDelete);
}
}
}
更新:
似乎从Typescript ver 0.9.1开始,你可以通过使用lambda字段初始化器来实现相同的结果:
class VM {
public deleteItem = (emailToDelete: string) => {
this.emails.remove(emailToDelete);
}
}
答案 1 :(得分:24)
手套人!只需将$ parent绑定为:
<a href="#" data-bind="click: $parent.deleteItem.bind($parent)">Delete</a>
答案 2 :(得分:6)
declare class Email { }
declare class ObservableArray {
remove(any): void;
}
class MyViewModel {
public emails : ObservableArray;
constructor() {
Rebind(this);
}
public deleteItem(emailToDelete: Email) {
this.emails.remove(emailToDelete);
}
}
function Rebind(obj : any)
{
var prototype = <Object>obj.constructor.prototype;
for (var name in prototype) {
if (!obj.hasOwnProperty(name)
&& typeof prototype[name] === "function") {
var method = <Function>prototype[name];
obj[name] = method.bind(obj);
}
}
}
您可能需要Function.bind()
的填充:
// Polyfill for Function.bind(). Slightly modified version of
// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind#Compatibility
if (typeof Function.prototype.bind !== "function") {
Function.prototype.bind = function(oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = <any[]> Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP && oThis ? this: oThis, aArgs.concat());
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
答案 3 :(得分:6)
我的最终解决方案是一个基类,它将所有原型函数重新绑定到构造函数上。很像Markus Jarderot的解决方案。
class BaseClass {
constructor() {
for (var i in this) {
if (!this.hasOwnProperty(i) && typeof (this[i]) === 'function' && i != 'constructor') {
this[i] = this[i].bind(this);
}
}
}
}
优点:
PS:
您仍然需要绑定polyfill
我正在使用typesript 0.9.5
答案 4 :(得分:2)
加上我的2美分,还有一种肮脏的方式,它利用了Typescript编译器创建的变量_this来保持对此的引用:
public deleteItem(emailToDelete: string) {
var that = eval('_this');
// remove item from list
that.emails.remove(emailToDelete); // remove? in JS, really?
}
答案 5 :(得分:1)
我受到bind
答案的启发,想出了这个,我觉得它更容易阅读。
<a href="#" data-bind="click: function () {$parent.deleteItem()}">Delete</a>
将方法包装在lambda / anonymous函数中。不要忘记()。
答案 6 :(得分:1)
使用类似这样的数据绑定:
data-bind="click:$parent.deleteItem.bind($parent)"
将this
分配给that
,如下所示
public deleteItem(itemToDelete)
{
var that = this;
// remove item from list
that.emails.remove(itemToDelete);
}
答案 7 :(得分:0)
虽然我更喜欢马库斯的解决方案,但这是我以前用来解决这个问题的方法:
public fixThis(_this, func) {
return function () {
return _this[func].apply(_this, arguments);
};
}
<a href="#" data-bind="click: fixThis($parent, 'deleteItem')">Delete</a>
请注意,可以通过在方法名称之后添加其他参数来传递给该方法:
fixThis($parent, 'deleteItem', arg1, arg2);