Q.Promise 和 KO.mapping 没有将对象数组转换为正确的类型
Q.Promise and KO.mapping not Converting Array of Objects to Proper Type
我正在尝试过滤一个可观察数组,但 运行 遇到了问题,因为我认为 ko.utils.arrayFilter 方法将我模型的所有字段名称更改为小写。我应该注意到这个项目中正在使用 Typescript。
这是我的模特:
export class MyListModel {
constructor(jsObject?: {}) {
if (jsObject) {
ko.mapping.fromJS(jsObject, {}, this);
}
}
Text = ko.observable<string>();
Value = ko.observable<string>();
}
在我的 viewModel 中有以下字段:
inches = ko.observableArray<Models.MyListModel>([]);
在程序的另一部分中,我调用 filterInches() 方法来根据某些条件过滤数组。 value 参数是当前在下拉列表中选择的值。
filterInches(value) {
if (value == 6) {
var filtered = ko.utils.arrayFilter(this.inches(),
function (item) {
if (parseInt(item.Text()) <= 8)
return true;
});
this.filteredInches(filtered);
} else {
this.filteredInches(this.inches());
}
}
编译时不会抛出任何错误,但是当我在浏览器中 运行 应用程序时,我收到一条错误消息 "item.Text is not a function"。当我单步执行 Chrome 中的代码时,看起来 item 已转换为具有文本和值字段的匿名对象。这些字段现在是小写的,我认为这是导致我 运行 遇到的问题的原因。是什么导致了这种行为?
编辑:
我正在处理这段代码的不同但相关的部分,我想我开始明白为什么它不起作用了。我相信它与 Q Promise 库有关,但我对该库的了解还不够,无法弄清楚为什么它不起作用(是的,我阅读了文档)。我认为编写这段代码的开发人员没有意识到它并没有按照他们认为的那样去做。
为了验证是否有问题,我尝试的第一件事是修改模型的 属性 名称:
export class MyListModel {
constructor(jsObject?: {}) {
if (jsObject) {
ko.mapping.fromJS(jsObject, {}, this);
}
}
Cat = ko.observable<string>();
Chicken = ko.observable<string>();
}
现在,如果我们回到修改后的 filterInches() 方法,我们会看到 item.Cat 在编译时有效,但是当我单步执行 Chrome 中的代码时,item 对象实际上没有属性 称为 Cat(未定义)。它的属性仍然是文本和值:
filterInches(value) {
if (value == 6) {
var filtered = ko.utils.arrayFilter(this.inches(),
function (item) {
if (parseInt(item.Cat()) <= 8)
return true;
});
this.filteredInches(filtered);
} else {
this.filteredInches(this.inches());
}
}
这告诉我我们从 json 检索的对象没有映射到 MyListModel 对象。我相信 MyListModel class 本身是好的。
我认为问题是由首先获取英寸的代码引起的:
refreshInches() {
this.DataService.getInches().done(entities => {
this.inches(entities);
});
}
然后getInches()方法如下:
getInches(): Q.Promise<Array<Models.MyListModel>> {
return Q($.getJSON(this._baseUrl + 'GetInches'));
}
我认为此代码的初衷是从端点异步获取英寸数据并将 json 数据转换为 MyListModel 对象。正如我之前所说,我对 Q.Promise 不够熟悉,不知道 getInches() 方法可能有什么问题。我很清楚,它只是从 JSON 数据中返回一个匿名对象数组。
作为参考,从端点返回的 json 对象如下所示:
[{"text":"0","value":"0"},{"text":"1","value":"1"},...]
有人知道如何改进 getInches() 方法来完成它应该做的事情吗?
根据您的代码,getInches 应该 return a Q.Promise<Array<Models.MyListModel>>
,即 MyListModel
对象数组的承诺。
但是,以目前的形式:
getInches(): Q.Promise<Array<Models.MyListModel>> {
return Q($.getJSON(this._baseUrl + 'GetInches'));
}
它不会那样做。以上 return 是对 <whatever the server gives you>
的承诺,在本例中显然是一个普通对象数组。
要更改它以匹配假定的类型,我们可以这样做
getInches(): Q.Promise<Array<Models.MyListModel>> {
var jqXhr = $.getJSON(this._baseUrl + 'GetInches');
return Q(jqXhr).then(data => {
return data.map(item => {
return new Models.MyListModel(item);
});
});
// or, if you must
return Q(jqXhr).then(data => data.map(item => new Models.MyListModel(item)));
}
所以现在我们可以将新创建的 MyListModel
个实例存储在一个可观察对象中:
refreshInches() {
this.DataService.getInches().done(this.inches);
}
注意this.inches
是一个observable,而observable是函数,这让我们可以直接将其作为回调使用。
用作承诺处理程序的函数将接收承诺值作为其第一个参数。可观察对象将存储您调用它时使用的第一个参数的值,因此非常适合。
此外,您的 filteredInches
方法太复杂了。不要让它成为你需要调用的函数,而是让它成为一个依赖于你的视图模型中的一些可观察对象的计算。这样就永远不会和其他的不一致了。
this.filteredInches = ko.pureComputed(() => {
var value = this.value();
return ko.utils.arrayFilter(this.inches(), item => {
value != 6 || +item.Text() <= 8;
});
});
查看您的视图模型创建,您可能希望在某处有一个数字可观察(或计算),这样您就不需要记住类型转换 Text
属性在计算中。
我正在尝试过滤一个可观察数组,但 运行 遇到了问题,因为我认为 ko.utils.arrayFilter 方法将我模型的所有字段名称更改为小写。我应该注意到这个项目中正在使用 Typescript。
这是我的模特:
export class MyListModel {
constructor(jsObject?: {}) {
if (jsObject) {
ko.mapping.fromJS(jsObject, {}, this);
}
}
Text = ko.observable<string>();
Value = ko.observable<string>();
}
在我的 viewModel 中有以下字段:
inches = ko.observableArray<Models.MyListModel>([]);
在程序的另一部分中,我调用 filterInches() 方法来根据某些条件过滤数组。 value 参数是当前在下拉列表中选择的值。
filterInches(value) {
if (value == 6) {
var filtered = ko.utils.arrayFilter(this.inches(),
function (item) {
if (parseInt(item.Text()) <= 8)
return true;
});
this.filteredInches(filtered);
} else {
this.filteredInches(this.inches());
}
}
编译时不会抛出任何错误,但是当我在浏览器中 运行 应用程序时,我收到一条错误消息 "item.Text is not a function"。当我单步执行 Chrome 中的代码时,看起来 item 已转换为具有文本和值字段的匿名对象。这些字段现在是小写的,我认为这是导致我 运行 遇到的问题的原因。是什么导致了这种行为?
编辑: 我正在处理这段代码的不同但相关的部分,我想我开始明白为什么它不起作用了。我相信它与 Q Promise 库有关,但我对该库的了解还不够,无法弄清楚为什么它不起作用(是的,我阅读了文档)。我认为编写这段代码的开发人员没有意识到它并没有按照他们认为的那样去做。
为了验证是否有问题,我尝试的第一件事是修改模型的 属性 名称:
export class MyListModel {
constructor(jsObject?: {}) {
if (jsObject) {
ko.mapping.fromJS(jsObject, {}, this);
}
}
Cat = ko.observable<string>();
Chicken = ko.observable<string>();
}
现在,如果我们回到修改后的 filterInches() 方法,我们会看到 item.Cat 在编译时有效,但是当我单步执行 Chrome 中的代码时,item 对象实际上没有属性 称为 Cat(未定义)。它的属性仍然是文本和值:
filterInches(value) {
if (value == 6) {
var filtered = ko.utils.arrayFilter(this.inches(),
function (item) {
if (parseInt(item.Cat()) <= 8)
return true;
});
this.filteredInches(filtered);
} else {
this.filteredInches(this.inches());
}
}
这告诉我我们从 json 检索的对象没有映射到 MyListModel 对象。我相信 MyListModel class 本身是好的。
我认为问题是由首先获取英寸的代码引起的:
refreshInches() {
this.DataService.getInches().done(entities => {
this.inches(entities);
});
}
然后getInches()方法如下:
getInches(): Q.Promise<Array<Models.MyListModel>> {
return Q($.getJSON(this._baseUrl + 'GetInches'));
}
我认为此代码的初衷是从端点异步获取英寸数据并将 json 数据转换为 MyListModel 对象。正如我之前所说,我对 Q.Promise 不够熟悉,不知道 getInches() 方法可能有什么问题。我很清楚,它只是从 JSON 数据中返回一个匿名对象数组。
作为参考,从端点返回的 json 对象如下所示:
[{"text":"0","value":"0"},{"text":"1","value":"1"},...]
有人知道如何改进 getInches() 方法来完成它应该做的事情吗?
根据您的代码,getInches 应该 return a Q.Promise<Array<Models.MyListModel>>
,即 MyListModel
对象数组的承诺。
但是,以目前的形式:
getInches(): Q.Promise<Array<Models.MyListModel>> {
return Q($.getJSON(this._baseUrl + 'GetInches'));
}
它不会那样做。以上 return 是对 <whatever the server gives you>
的承诺,在本例中显然是一个普通对象数组。
要更改它以匹配假定的类型,我们可以这样做
getInches(): Q.Promise<Array<Models.MyListModel>> {
var jqXhr = $.getJSON(this._baseUrl + 'GetInches');
return Q(jqXhr).then(data => {
return data.map(item => {
return new Models.MyListModel(item);
});
});
// or, if you must
return Q(jqXhr).then(data => data.map(item => new Models.MyListModel(item)));
}
所以现在我们可以将新创建的 MyListModel
个实例存储在一个可观察对象中:
refreshInches() {
this.DataService.getInches().done(this.inches);
}
注意this.inches
是一个observable,而observable是函数,这让我们可以直接将其作为回调使用。
用作承诺处理程序的函数将接收承诺值作为其第一个参数。可观察对象将存储您调用它时使用的第一个参数的值,因此非常适合。
此外,您的 filteredInches
方法太复杂了。不要让它成为你需要调用的函数,而是让它成为一个依赖于你的视图模型中的一些可观察对象的计算。这样就永远不会和其他的不一致了。
this.filteredInches = ko.pureComputed(() => {
var value = this.value();
return ko.utils.arrayFilter(this.inches(), item => {
value != 6 || +item.Text() <= 8;
});
});
查看您的视图模型创建,您可能希望在某处有一个数字可观察(或计算),这样您就不需要记住类型转换 Text
属性在计算中。