Twitter bootstrap 如何在Knockoutjs中将categoryId从一个ViewModel传递到另一个ViewModel-Error categoryId undefined

Twitter bootstrap 如何在Knockoutjs中将categoryId从一个ViewModel传递到另一个ViewModel-Error categoryId undefined,twitter-bootstrap,knockout.js,asp.net-mvc-5,Twitter Bootstrap,Knockout.js,Asp.net Mvc 5,我有两个引导下拉列表,当我在第一个中选择一个类别时,第二个应该根据第一个的categoryId填充。我试图使用subscribe函数将categoryId从reportCategoryViewModel传递到reportTypeViewModel,但它没有按预期工作,我得到了未定义的错误categoryId var shouter = new ko.subscribable(); function reportCategoryViewModel() { ... self.selectedRepo

我有两个引导下拉列表,当我在第一个中选择一个类别时,第二个应该根据第一个的categoryId填充。我试图使用subscribe函数将categoryId从reportCategoryViewModel传递到reportTypeViewModel,但它没有按预期工作,我得到了未定义的错误categoryId

var shouter = new ko.subscribable();
function reportCategoryViewModel() {
...
self.selectedReportCategoryName = ko.observable();
self.selectReportCategory = function (reportCategoryList) {
    self.selectedReportCategoryName(reportCategoryList.reportCategoryName);
    var categoryId = reportCategoryList.reportCategoryId;
这段代码运行良好,我用一个警报对其进行了测试,当我选择一个类别时,警报显示正确的categoryId:

    alert("reportCategoryViewModel - categoryId " + categoryId);

    self.reportCategoryId.subscribe(function (categoryId) {
        shouter.notifySubscribers(categoryId, "categoryIdForSelectingTypes");
    });
};

function reportTypeViewModel() {
...
self.selectedCategoryId = ko.observable();
self.reportTypes = ko.observableArray();
self.selectedReportType = ko.observable();
self.selectReportType = function (reportTypeList) {
    self.selectedReportType(reportTypeList.reportTypeName);
};
var uriReportType = 'api/reporttypes/' + self.selectedCategoryId();
var reportTypeArray = [];
$.getJSON(uriReportType)
    .done(function (data) {
        $.each(data, function (index, item) {
            reportTypeArray.push(item);
            self.reportTypes(reportTypeArray);
        });
    });
}
$(document).ready(function () {
var masterViewModel = (function () {
    this.reportCategoryViewModel = new reportCategoryViewModel();
    this.reportTypeViewModel = new reportTypeViewModel();
})();

ko.applyBindings(masterViewModel);
});
如果我在下面的标题中正确地传递了类别ID,我不确定:

shouter.subscribe(function (categoryId) {
    self.selectedCategoryId(categoryId);
}, self, "categoryIdForSelectingTypes");
发生此错误是因为下面的selft.selectedCategoryId()不包含有效的categoryId:

    alert("reportCategoryViewModel - categoryId " + categoryId);

    self.reportCategoryId.subscribe(function (categoryId) {
        shouter.notifySubscribers(categoryId, "categoryIdForSelectingTypes");
    });
};

function reportTypeViewModel() {
...
self.selectedCategoryId = ko.observable();
self.reportTypes = ko.observableArray();
self.selectedReportType = ko.observable();
self.selectReportType = function (reportTypeList) {
    self.selectedReportType(reportTypeList.reportTypeName);
};
var uriReportType = 'api/reporttypes/' + self.selectedCategoryId();
var reportTypeArray = [];
$.getJSON(uriReportType)
    .done(function (data) {
        $.each(data, function (index, item) {
            reportTypeArray.push(item);
            self.reportTypes(reportTypeArray);
        });
    });
}
$(document).ready(function () {
var masterViewModel = (function () {
    this.reportCategoryViewModel = new reportCategoryViewModel();
    this.reportTypeViewModel = new reportTypeViewModel();
})();

ko.applyBindings(masterViewModel);
});

错误:GET 400(错误请求)

KO邮箱示例 我用ko.postbox更新了小提琴

首先加载ko.postbox,然后在创建observable时设置一个发布通道,例如

self.reportCategoryId = ko.observable().publishOn('reportCategoryID');
我已经注释掉了shouter代码-最好不要弄乱全局空间,而是坚持vm到vm的通信(通过邮箱)或集中通信(根据我的github示例)

你只需要一个ko.postbox.subscribe就可以收到这些活动

ko.postbox.subscribe('reportCategoryID', function(categoryId) {
    self.selectedCategoryId(categoryId);
    alert("categoryId VM2" + categoryId);
}, self, "categoryIdForSelectingTypes");
具有ViewModel的中央服务提供商 我倾向于使用中央服务提供商(singleton)来保存数据,并提供函数来操作数据或通过api获取新数据等

比如说

const ko = require('knockout');
const CentralState = {
    signIn : componentName => signIn(componentName),
    signedInComponents : ko.observableArray([]),
};
const signIn = (componentName) => {
    if (CentralState.signedInComponents().indexOf(componentName) < 0) {
        CentralState.signedInComponents.push(componentName);
    }
};
module.exports = CentralState;
const ko=require('knockout');
常数中心状态={
signIn:componentName=>signIn(componentName),
签名组件:ko.observableArray([]),
};
常量符号=(组件名称)=>{
if(CentralState.SignedComponents().indexOf(componentName)<0){
CentralState.SignedComponents.push(componentName);
}
};
module.exports=CentralState;
您可以看到它在这里设置了两个服务提供商(一个用于api,一个用于state),包括Gulp和Babel转换,这样您就可以使用新的Javascript


无论哪种方式,您只需订阅observable中央服务提供商或ko.postbox“频道”,以便在其他视图模型更改影响您时获得更新。

请将您的代码编辑为a:添加一些视图代码,使JS代码语法正确,从而使其成为一个复制。去掉数据检索位。等等。(最好创建一个可运行的代码段。)@Jeroen我编辑了问题并添加了JSFIDLE代码。@ZotNet-你的FIDLE没有加载KO@brianlmerritt非常感谢。我现在将KO添加到外部资源,并将一些硬编码数据添加到self.reportCategories=KO.observableArray([…])谢谢!但是在我的例子中实现这个有点复杂,因为我开始学习KO。。。您能帮忙吗?完成了,但请看一下github示例,因为它既包括自定义组件和中央服务提供商,又支持ES6,因此您可以停止所有self=this pain并使用=>函数谢谢您的回复!我已经看过Github示例,但其中包含大量信息,我不知道如何在代码中应用它。。。intellisense在此行不起作用:self.selectedCategoryId=ko.observable(reportCategoryViewModel.categoryId);当我在reportCategoryViewModel之后键入点以获取categoryId时,不同选项中没有categoryId。此行:警报(“类别ID VM2”+类别ID);当页面加载时呈现未定义的categoryId,但当我选择一个类别时,什么都不会发生。不用担心,但是当可观察到的更改时,postbox现在会更新其他视图模型。只需在开始时设置所需的类别,并根据需要处理类别更改。类别应由用户选择,没有默认类别,当我选择类别时,该参数在第二个ViewModel中不可访问。。。我是否也应该使用您在下面描述的代码“Central ServiceProvider with ViewModel”?