【发布时间】:2016-04-30 12:39:15
【问题描述】:
当我使用foreach 数据绑定时,它似乎打破了$root 上下文以进行淘汰赛。
当这种情况发生时,this 指的是一个元素 (user),它是 viewmodel (page) 的子元素和 foreach 元素 (requests) 的父元素,它应该引用 viewmodel (page)。
我在 foreach 之外引用 $root 没有问题 - 它在正确的上下文中调用正确的方法。
适用的 HTML:
<div id="home-page-view" class="view" data-bind="if: status() == AppStatus.Home">
<button data-bind="click: $root.switchState">Switch To Friend Requests</button>
</div>
Typescript 的作用:
public switchState() {
if (this.status() == AppStatus.Home) {
this.status(AppStatus.FriendRequests); //this refers to viewmodel (page)
} else {
this.status(AppStatus.Home);
}
}
但是,在 foreach 中,像data-bind="click: $root.acceptFriendRequest" 这样绑定的按钮成功调用了它们的方法,但this 指的是user,而不是page。
HTML 损坏的地方:
<div id="friend-requests-view" class="view" data-bind="if: status() == AppStatus.FriendRequests">
<h1>Friend Requests</h1>
<p>View your pending friend requests.</p>
<div data-bind="with: user">
<div data-bind="foreach: requests">
<div>
<h2 data-bind="text: firstName"></h2>
<p data-bind="text: lastName"></p>
</div>
<div>
<input type="button" value="Accept" data-bind="click: $root.acceptFriendRequest" />
<input type="button" value="Deny" data-bind="click: $root.rejectFriendRequest" />
</div>
</div>
</div>
</div>
打字稿损坏的地方:
public acceptFriendRequest(newFriend: UserModel) {
this.respondToFriendRequest(true, newFriend);
}
public rejectFriendRequest(notFriend: UserModel) {
this.respondToFriendRequest(false, notFriend);
}
即使在其损坏的 HTML 中,status() 之前的 4 行隐含地引用了正确的 $root。
这里发生了什么导致this 引用page.user 而不是page?鉴于在其他情况下this 指的是page,看来$root 应该总是指回page。
MCVE:
Page.html
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<script type="text/javascript" src="/Scripts/jquery-2.1.4.js"></script>
<script type="text/javascript" src="/Scripts/jquery-ui-1.11.4.js"></script>
<script type="text/javascript" src="/Scripts/knockout-3.3.0.js"></script>
<script type="text/javascript" src="/Scripts/knockout.mapping-latest.js"></script>
<script type="text/javascript" src="app.js"></script>
<script type="text/javascript" src="DTO/DTOs.js"></script>
</head>
<body>
<div id="home-page-view" class="view" data-bind="if: status() == AppStatus.Home">
<button data-bind="click: $root.switchState">Switch To Friend Requests</button>
</div>
<div id="friend-requests-view" class="view" data-bind="if: status() == AppStatus.FriendRequests">
<h1>Friend Requests</h1>
<p>View your pending friend requests.</p>
<div data-bind="with: user">
<div data-bind="foreach: requests">
<div>
<h2 data-bind="text: firstName"></h2>
<p data-bind="text: lastName"></p>
</div>
<div>
<input type="button" value="Accept" data-bind="click: $root.acceptFriendRequest" />
<input type="button" value="Deny" data-bind="click: $root.rejectFriendRequest" />
</div>
</div>
</div>
</div>
</body>
</html>
App.ts
/// <reference path="Scripts/typings/jquery/jquery.d.ts" />
/// <reference path="Scripts/typings/jqueryui/jqueryui.d.ts" />
/// <reference path="Scripts/typings/knockout/knockout.d.ts" />
/// <reference path="Scripts/typings/knockout.mapping/knockout.mapping.d.ts" />
var page: App;
$(document).ready(function () {
$.ajaxSetup({ cache: false });
page = new App();
ko.applyBindings(page);
});
class App {
public user: KnockoutObservable<UserModel>;
public status: KnockoutObservable<AppStatus> = ko.observable(AppStatus.Home);
constructor() {
this.user = ko.observable(new UserModel());
var us: User = {firstName: "Chip", lastName: "Dipson" };
this.user(ko.mapping.fromJS(us));
this.user().requests.push(new UserModel());
}
public switchState() {
if (this.status() == AppStatus.Home) {
this.status(AppStatus.FriendRequests);
} else {
this.status(AppStatus.Home);
}
}
public acceptFriendRequest(newFriend: UserModel) {
this.respondToFriendRequest(true, newFriend); //this is wrong
}
public rejectFriendRequest(notFriend: UserModel) {
this.respondToFriendRequest(false, notFriend); //this is wrong
}
private respondToFriendRequest(accepted: boolean, requester: UserModel) {
//do some ajax stuff
}
}
enum AppStatus {
Home, FriendRequests
}
DTOs.ts
class User {
firstName: string;
lastName: string;
requests: User[];
}
class UserModel {
firstName: KnockoutObservable<string> = ko.observable("");
lastName: KnockoutObservable<string> = ko.observable("");
requests: KnockoutObservableArray<UserModel> = ko.observableArray<UserModel>(null);
}
【问题讨论】:
标签: javascript html knockout.js typescript