Javascript 敲除映射插件检索到的viewModel对象和新对象之间的不一致性

Javascript 敲除映射插件检索到的viewModel对象和新对象之间的不一致性,javascript,knockout.js,Javascript,Knockout.js,我正在尝试将新对象添加到我加载的viewmodel中,如下所示: <script type="text/javascript"> var myViewModel = {}; var Fighter = function (data) { var self = this; self.Name = ko.observable(data.Name); self.Country = ko.observable(data.Cou

我正在尝试将新对象添加到我加载的viewmodel中,如下所示:

<script type="text/javascript">
    var myViewModel = {};

    var Fighter = function (data) {
        var self = this;
        self.Name = ko.observable(data.Name);
        self.Country = ko.observable(data.Country);
        self.TopSpeed = ko.observable(data.TopSpeed);
    };

    var WarCraft = function (data) {
        var self = this;
        self.fighter = ko.observable(data.fighter);
    };

    var dataMappingOptions = {
        key: function (data) {
            return data.id;
        },
        create: function (options) {
            if (data.id == 1)
                return new Fighter(options.data);
            else
                if (data.id == 2)
                    return new WarCraft(options.data);
        }
    };

    $.getJSON("/Home/GetServerData", function (model) {
        ko.mapping.fromJS(model, dataMappingOptions, myViewModel);

        ko.applyBindings(myViewModel);

    }).error(function () { alert("Oops!") }).success(function () { alert("Yeah!") });


    myViewModel.AddToData = function () {
        var newFighter = new Fighter(
                        {
                            id : 1,
                            Name: myViewModel.warCraft.fighter.Name(),
                            Country: myViewModel.warCraft.fighter.Country(),
                            TopSpeed: myViewModel.warCraft.fighter.TopSpeed() 
                        });
        var newWarCraft = new WarCraft({ id: 2, fighter: newFighter });
        myViewModel.WW2Machines.push(newWarCraft);
    }.bind(myViewModel);


</script>

var myViewModel={};
var=功能(数据){
var self=这个;
self.Name=ko.observable(data.Name);
self.Country=ko.observable(data.Country);
self.TopSpeed=ko.可观测(data.TopSpeed);
};
var魔兽争霸=函数(数据){
var self=这个;
self.fighter=ko.observable(data.fighter);
};
var dataMappingOptions={
键:功能(数据){
返回data.id;
},
创建:函数(选项){
如果(data.id==1)
返回新战斗机(选项.数据);
其他的
如果(data.id==2)
返回新魔兽(options.data);
}
};
$.getJSON(“/Home/GetServerData”,函数(模型){
fromJS(模型,dataMappingOptions,myViewModel);
应用绑定(myViewModel);
}).error(函数(){alert(“Oops!”)}).success(函数(){alert(“Yeah!”)});
myViewModel.AddToData=函数(){
var newFighter=新战斗机(
{
id:1,
名称:myViewModel.warCraft.fighter.Name(),
国家:myViewModel.warCraft.fighter.Country(),
TopSpeed:myViewModel.warCraft.fighter.TopSpeed()
});
var newWarCraft=newWarCraft({id:2,fighter:newFighter});
myViewModel.WW2Machines.push(新魔兽);
}.bind(myViewModel);
服务器端模型:

 DataModel model = new DataModel();
 model.warCraft = new WarCraft();
 model.warCraft.fighter = new Fighter();
 model.warCraft.fighter.Name = "Spitfire";
 model.WW2Machines = new List<WarCraft>();

 WarCraft w1 = new WarCraft();
 w1.fighter = new Fighter() { Name = "Spitfire" };
 model.WW2Machines.Add(w1);

 WarCraft w2 = new WarCraft();
 w2.fighter = new Fighter() { Name = "Hurricane" };
 model.WW2Machines.Add(w2);

 WarCraft w3 = new WarCraft();
 w3.fighter = new Fighter() { Name = "Tomcat" };
 model.WW2Machines.Add(w3);
DataModel=newdatamodel();
model.warCraft=新魔兽();
model.warCraft.fighter=新战斗机();
model.warCraft.fighter.Name=“喷火”;
model.WW2Machines=新列表();
魔兽争霸w1=新魔兽争霸();
w1.fighter=新战斗机(){Name=“Spitfire”};
型号WW2机器添加(w1);
魔兽争霸w2=新魔兽争霸();
w2.fighter=newfighter(){Name=“Hurricane”};
模型ww2机器添加(w2);
魔兽争霸w3=新魔兽争霸();
w3.fighter=newfighter(){Name=“Tomcat”};
model.WW2Machines.Add(w3);
。。。Ajax调用调用的方法,用于初始化和发送数据:

DataModel model = new DataModel();
model.warCraft = new WarCraft();
model.warCraft.fighter = new Fighter();
model.warCraft.fighter.Name = "Spitfire";
model.WW2Machines = new List<WarCraft>();

WarCraft w1 = new WarCraft();
w1.fighter = new Fighter() { Name = "Spitfire" };
model.WW2Machines.Add(w1);

WarCraft w2 = new WarCraft();
w2.fighter = new Fighter() { Name = "Hurricane" };
model.WW2Machines.Add(w2);

WarCraft w3 = new WarCraft();
w3.fighter = new Fighter() { Name = "Tomcat" };
model.WW2Machines.Add(w3);

return Json(model, JsonRequestBehavior.AllowGet);
DataModel=newdatamodel();
model.warCraft=新魔兽();
model.warCraft.fighter=新战斗机();
model.warCraft.fighter.Name=“喷火”;
model.WW2Machines=新列表();
魔兽争霸w1=新魔兽争霸();
w1.fighter=新战斗机(){Name=“Spitfire”};
型号WW2机器添加(w1);
魔兽争霸w2=新魔兽争霸();
w2.fighter=newfighter(){Name=“Hurricane”};
模型ww2机器添加(w2);
魔兽争霸w3=新魔兽争霸();
w3.fighter=newfighter(){Name=“Tomcat”};
model.WW2Machines.Add(w3);
返回Json(model,JsonRequestBehavior.AllowGet);
。和我的html:

<div id="show" data-bind="visible: WW2Machines().length>0">
    <h2>Information Display:</h2>
    NewNumber : <span data-bind="text: WW2Machines().length"></span>
    <ul data-bind="foreach: WW2Machines">
        <li>
            Name: <span data-bind="text: fighter.Name"></span>
            <br>&nbsp;</br>
        </li>
    </ul>
</div>

<div id="theForm">
    @using (Html.BeginForm())
    {
        <legend WW2 Fighter Planes: >
            <fieldset>
                Name:
                <br>&nbsp;</br>
                <select data-bind="value: warCraft.fighter.Name, optionsCaption: 'Please Select . . '">
                    <option>Mosquito</option>
                    <option>Mustang</option>
                    <option>Messerschmidt 109</option>
                </select>
                <br>&nbsp;</br>
                <span data-bind="text: warCraft.fighter.Name"></span>
                <br>&nbsp;</br>

                Country:
                <br>&nbsp;</br>
                <select data-bind="value: warCraft.fighter.Country, optionsCaption: 'Please Select . . '">
                    <option>England</option>
                    <option>USA</option>
                    <option>Germany</option>
                </select>
                <br>&nbsp;</br>
                <span data-bind="text: warCraft.fighter.Country"></span>
                <br>&nbsp;</br>

                Top Speed:
                <br>&nbsp;</br>
                <select data-bind="value: warCraft.fighter.TopSpeed, optionsCaption: 'Please Select . . '">
                    <option>390 km/h</option>
                    <option>275 km/h</option>
                    <option>250 km/h</option>
                </select>
                <br>&nbsp;</br>
                <span data-bind="text: warCraft.fighter.TopSpeed"></span>                

                <input type="button" data-bind="click: AddToData">Add</input>

            </fieldset>

        </legend>

}

信息显示:
新号码:
  • 姓名:

@使用(Html.BeginForm()) { 姓名:

蚊子 野马 梅塞施密特109



国家:

英格兰 美国 德国



最高速度:

390公里/小时 275公里/小时 时速250公里

添加 }

问题是,我的添加按钮被触发,并将行添加到显示区域,但它们是空的。在Firefox的调试器控制台中,我看到我可以引用从服务器发送的行,以及通过添加按钮添加的行(正确包含数据),但有一个令人费解的区别: 我使用以下语法访问现有行:

myViewModel.WW2Machines()[0]。fighter.Name()

。以及使用以下语法添加的行:

myViewModel.WW2Machines()[3].fighter().Name()


。对于各自的下标,在彼此之间切换语法会抛出一个错误。这可能是关于为什么我的行被添加为空白的线索,但我不知道为什么?有人能帮忙吗?

至少有一部分问题,以及你在底部遇到的令人费解的差异的解释是,你稍后添加的行使
魔兽争霸
成为可观察的,而映射插件没有这样做

所以你可以交换这个:

var WarCraft = function (data) {
    var self = this;
    self.fighter = ko.observable(data.fighter);
};
为此

var WarCraft = function (data) {
    var self = this;
    self.fighter = data.fighter;
};
您应该能够以相同的方式访问映射数据和添加的数据:

myViewModel.WW2Machines()[0].fighter.Name()

阿德里安,你能解释一下为什么映射插件不能让魔兽争霸变得可见吗?我认为使用插件映射的所有对象和子属性都默认为可观察。谢谢,

太好了!谢谢!:):)这并不是问题的真正答案。你应该把它作为一个评论发布到被接受的答案上。我想知道映射插件是如何决定哪些是可观察的,哪些是不可观察的。难道不是所有的对象和组成的子对象都应该可以通过映射插件观察到吗?再次感谢。