请参阅下面的更新代码
我正在尝试使用打字稿和打字稿,但似乎我无法将我的打字稿视图模型绑定到我的视图......似乎我有this
的问题,但我不明白为什么...
调用this.UserList
方法
Fill
未定义
这是我的viewModel:
module ViewModels {
export class UserViewModel {
constructor() {
this.UserList = ko.observableArray<KnockoutObservable<Models.User>>([]);
this.RemoveItem = <(user: KnockoutObservable<Models.User>) => void> this.RemoveItem.bind(this);
this.AcceptItem = <(user: Models.User) => void> this.AcceptItem.bind(this);
this.AddItem = <() => void> this.AddItem.bind(this);
}
public UserList: KnockoutObservableArray<KnockoutObservable<Models.User>>;
public Fill() {
$.ajax({
type: "POST",
url: "/Guest/LoadGuest/",
success: data=> {
$(data).each((index: any, item)=> {
var guest = new Models.User();
guest.FirstName = ko.observable(item.firstName);
guest.LastName = ko.observable(item.lastName);
guest.IsNew = ko.observable(false);
this.UserList.push(ko.observable(guest));
});
}
});
}
public AddItem() {
var guest = new Models.User();
guest.FirstName = ko.observable("");
guest.LastName = ko.observable("");
guest.IsNew = ko.observable(true);
this.UserList.push(ko.observable(guest));
}
public AcceptItem(user: Models.User) {
user.IsNew = ko.observable(false);
}
public RemoveItem(user: KnockoutObservable<Models.User>) {
this.UserList.remove(user);
}
}
}
这是我的观点:
<table>
<thead>
<tr><th>Prénom</th><th>Nom de famille</th></tr>
</thead>
<tbody data-bind="foreach: UserList">
<tr data-bind="if:IsNew">
<td><input type="text" data-bind="text: FirstName" /></td>
<td><input type="text" data-bind="text: LastName" /></td>
<td><a data-bind="click:$parent.AcceptItem">OK</a><a data-bind="click:$parent.RemoveItem">Annuler</a></td>
</tr>
<tr data-bind="if:!IsNew">
<td data-bind="text: FirstName"></td>
<td data-bind="text: LastName"></td>
<td></td>
</tr>
</tbody>
</table>
<a id="AddGuest" data-bind="click:AddItem">Add</a>
@section scripts{
<script src="~/Scripts/models/ModelBase.js"></script>
<script src="~/Scripts/models/User.js"></script>
<script src="~/Scripts/viewmodels/UserViewModel.js"></script>
<script>
var vm = new ViewModels.UserViewModel();
vm.Fill();
ko.applyBindings(vm);
</script>
}
这是我的模特:
module Models{
export class User extends Models.ModelBase {
constructor() {
super();
}
public FirstName: KnockoutObservable<string>;
public LastName: KnockoutObservable<string>;
public Age: KnockoutObservable<Age>;
}
export class Age {
public ID: KnockoutObservable<number>;
public Description: KnockoutObservable<string>;
}
}
帮助改善目标的新工作代码:
视图模型:
module ViewModels {
export class UserViewModel {
constructor() {
}
public UserList: KnockoutObservableArray<Models.User> = ko.observableArray<Models.User>([]);
public Fill = () => {
$.ajax({
type: "POST",
url: "/Guest/LoadGuest/",
success: data=> {
for (var i = 0; i < data.length; i++) {
var item = data[i];
var guest = new Models.User();
guest.FirstName(item.firstName);
guest.LastName(item.lastName);
guest.Age().Description("Test Age");
guest.IsNew(false);
this.UserList.push(guest);
}
}
});
}
public AddItem = () => {
var guest = new Models.User();
guest.FirstName = ko.observable("");
guest.LastName = ko.observable("");
guest.IsNew(true);
this.UserList.push(guest);
}
public AcceptItem = (user: Models.User) => {
user.IsNew(false);
}
public RemoveItem = (user: Models.User) => {
this.UserList.remove(user);
}
}
}
型号:
module Models{
export class ModelBase{
constructor() {
this.IsNew = ko.observable(false);
}
public IsNew: KnockoutObservable<boolean>;
}
export interface IUser {
FirstName: KnockoutObservable<string>;
LastName: KnockoutObservable<string>;
Age: KnockoutObservable<Age>;
}
export class User extends Models.ModelBase implements IUser {
constructor() {
super();
this.FirstName = ko.observable("");
this.LastName = ko.observable("");
this.Age = ko.observable(new Age());
}
public FirstName: KnockoutObservable<string>;
public LastName: KnockoutObservable<string>;
public Age: KnockoutObservable<Age>;
}
export class Age {
constructor() {
this.ID = ko.observable(null);
this.Description = ko.observable("");
}
public ID: KnockoutObservable<number>;
public Description: KnockoutObservable<string>;
}
}
查看:
<table>
<thead>
<tr><th>Prénom</th><th>Nom de famille</th><th>Age</th></tr>
</thead>
<tbody data-bind="foreach: UserList">
<tr data-bind="ifnot:$data.IsNew">
<td data-bind="text: FirstName"></td>
<td data-bind="text: LastName"></td>
<td data-bind="text: Age().Description"></td>
</tr>
<tr data-bind="if:$data.IsNew">
<td><input type="text" data-bind="value: FirstName" /></td>
<td><input type="text" data-bind="value: LastName" /></td>
<td><input type="text" data-bind="value: Age().Description" /></td>
<td><a data-bind="click:$root.AcceptItem">OK</a><a data-bind="click:$root.RemoveItem">Annuler</a></td>
</tr>
</tbody>
</table>
<a id="AddGuest" data-bind="click:AddItem">Add</a>
@section scripts{
<script src="~/Scripts/models/ModelBase.js"></script>
<script src="~/Scripts/models/User.js"></script>
<script src="~/Scripts/viewmodels/UserViewModel.js"></script>
<script>
var vm = new ViewModels.UserViewModel();
vm.Fill();
ko.applyBindings(vm);
</script>
}
答案 0 :(得分:9)
如果您希望将this
绑定到UserViewModel
,那么可以使用此方法:
module ViewModels {
export class UserViewModel {
UserList: KnockoutObservableArray<KnockoutObservable<Models.User>> = ko.observableArray<KnockoutObservable<Models.User>>([]);
Fill = () => {
$.ajax({
type: "POST",
url: "/Guest/LoadGuest/",
success: data => {
$(data).each((index: any, item)=> {
var guest = new Models.User();
guest.FirstName = ko.observable(item.firstName);
guest.LastName = ko.observable(item.lastName);
guest.IsNew = ko.observable(false);
this.UserList.push(ko.observable(guest));
});
}
});
}
AddItem = () => {
var guest = new Models.User();
guest.FirstName = ko.observable("");
guest.LastName = ko.observable("");
guest.IsNew = ko.observable(true);
this.UserList.push(ko.observable(guest));
}
AcceptItem = (user: Models.User) => {
user.IsNew = ko.observable(false);
}
RemoveItem = (user: KnockoutObservable<Models.User>) => {
this.UserList.remove(user);
}
}
}
这是demo
的TypeScript Playground您可以阅读此处使用的方法的说明:http://blogs.msdn.com/b/typescript/archive/2013/08/06/announcing-0-9-1.aspx(选中“更好'此'处理方式)
顺便说一句,我怀疑你有KnockoutObservable<Models.User>
你应该拥有Models.User
的位置,当你有this.UserList.push(ko.observable(guest));
时,你实际应该拥有this.UserList.push(guest);
。我没有更改代码示例,以防我错过了什么。
答案 1 :(得分:6)
此处的其他答案假设您对问题的描述是准确的。我决定实际测试你的代码。这是我发现的:
错误的each
功能。
$(data).each((index: any, item)=> {
这可能在技术上有效,但它应该是针对DOM节点的。您应该使用$.each
。
$.each(data, (index: any, item)=> {
在可观察的视图中包装视图模型对象。
this.UserList.push(ko.observable(guest));
这会破坏您的RemoveItem
功能。你应该只添加对象。
this.UserList.push(guest);
覆盖一个observable而不是设置它。
user.IsNew = ko.observable(false);
Knockout将无法在此处看到更改。您需要设置observable。
user.IsNew(false);
对<input>
元素使用错误的绑定。
<td><input type="text" data-bind="text: FirstName" /></td>
text
绑定是单向的。您需要使用value
。
<td><input type="text" data-bind="value: FirstName" /></td>
在表达式中不正确地使用observable。
<tr data-bind="if:!IsNew">
这测试observable本身是false
,它始终不是(因为它是一个函数)。您想测试observable的值是false
:!IsNew()
。更好的是,只需使用ifnot
绑定。
<tr data-bind="ifnot:IsNew">
答案 2 :(得分:3)
使用lamda语法。
只需更改此行
即可 public Fill() {
到此:
public Fill = () => {
在我们的代码库中,我发现我几乎不需要诉诸var self = this;
解决方法。
其他建议:
1)如果您将功能更改为使用lamda语法,则可以摆脱所有这些业务:
this.RemoveItem = <(user: KnockoutObservable<Models.User>) => void> this.RemoveItem.bind(this);
this.AcceptItem = <(user: Models.User) => void> this.AcceptItem.bind(this);
this.AddItem = <() => void> this.AddItem.bind(this);
2)只需初始化你声明它们的公共属性 - 在构造函数中执行它有很多冗余代码(即与上面相同)
而不是:
public UserList: KnockoutObservableArray<KnockoutObservable<Models.User>>;
这样做:
public UserList = ko.ObservableArray<Modesl.User>([]);
您的UsersList
对象仍然是强类型的,您的构造函数中不需要这一行:this.UserList = ko.observableArray<Models.User>([]);
请注意,我同意另一张海报,您可能实际上没有想要一个observable array of observables
所以为了清楚起见,我删除了那个古怪的东西。
答案 3 :(得分:1)
原因是当你在填充方法中时,'this'指的是一个新的上下文。为了保持'this'的含义,你可以使用像self这样的变量在树下进一步引用它 -
module ViewModels {
export class UserViewModel {
constructor() {
var self = this;
self.UserList = ko.observableArray<KnockoutObservable<Models.User>>([]);
self.RemoveItem = <(user: KnockoutObservable<Models.User>) => void> this.RemoveItem.bind(this);
self.AcceptItem = <(user: Models.User) => void> this.AcceptItem.bind(this);
self.AddItem = <() => void> this.AddItem.bind(this);
}
public UserList: KnockoutObservableArray<KnockoutObservable<Models.User>>;
public Fill() {
var self = this;
$.ajax({
type: "POST",
url: "/Guest/LoadGuest/",
success: data=> {
$(data).each((index: any, item)=> {
var guest = new Models.User();
guest.FirstName = ko.observable(item.firstName);
guest.LastName = ko.observable(item.lastName);
guest.IsNew = ko.observable(false);
self.UserList.push(ko.observable(guest));
});
}
});
}
}
}
答案 4 :(得分:1)
如果您按照接受的答案的建议将函数签名从MyFunc() { }
更改为lambda格式MyFunc = () => { }
,您会发现您的函数不再是您班级的共享原型函数,而是而是复制为每个类实例的函数变量。
另一种方法是更改点击绑定以使用JavaScript的 bind 功能强制this
的值作为您的视图模型:data-bind="click: $root.MyFunc.bind($root)"
。< / p>
请注意,$data
和点击event
对象仍会作为<{1}}的参数从Knockout传入,如 click binding 所述规格。如果您需要覆盖传递给MyFunc
的参数,只需将它们传递到MyFunc
之后的绑定函数中,如下所示:$root
。从技术上讲,这些参数将预先到Knockout提供的参数,并提供参数.bind($root, param1, param2)
。