KnockoutJS observableArray不在组件中更新

时间:2017-01-06 21:51:41

标签: knockout.js

我有一个由ko.mapping插件创建的Knockout视图模型。

var infoNeeded = [{
  "ProductPKUID":10069,
  "ProductID":"SW42",
  "ProductName":"Display Name of Product",
  "Quantity":1,
  "NeededInfo":[
    {
      "InfoTypeNeeded":0,
      "InfoGathered":null
    },
    {
      "InfoTypeNeeded":1,
      "InfoGathered":null}]}];
infoNeeded = ko.mapping.fromJS(infoNeeded);

请注意,在此示例中,viewmodel仅包含一个产品,但它是一个可包含更多产品的数组。该视图模型正在应用于这个HTML块,这似乎正在起作用。

<div id="additionalInfoNeeded" data-bind="foreach: infoNeeded">
    <span data-bind="text: ProductID"></span> - <span data-bind="text: ProductName"></span>
    <span data-bind="visible: Quantity > 1, text: '(Qty: ' + Quantity + ')'"></span>
    <div data-bind="foreach: NeededInfo">
        <div>
            Needs Info Type: <span data-bind="text: InfoTypeNeeded"></span>
            <div data-bind="if: (InfoTypeNeeded() === 1)">
              <species-edit params="value: $data, prodID: $parent.ProductID()"></species-edit>
            </div>
        </div>
    </div>
</div>

注意我在那里使用custom element(种类编辑),如果数组中此产品所需的信息是infoType = 1.我希望species-edit元素从服务器中获取物种列表与此productID相关,然后允许用户从该列表中选择。然后我希望我的主视图模型能够看到所选的物种。从服务器回来的物种json看起来像这样。

[{"ID":1,"Name":"BLUE CRAB","Chosen":false},{"ID":2,"Name":"EEL","Chosen":false},{"ID":5,"Name":"INSHORE FISH","Chosen":false},{"ID":6,"Name":"OFFSHORE FISH","Chosen":false},{"ID":7,"Name":"OTHER","Chosen":false},{"ID":8,"Name":"SHARK","Chosen":false},{"ID":9,"Name":"SHRIMP OR PRAWN","Chosen":false},{"ID":12,"Name":"AMERICAN SHAD","Chosen":false},{"ID":28,"Name":"SHELLFISH(OYSTER,CLAM,MUSSEL","Chosen":false}]

这是我的物种-edit.html:

<div>
    <div>What type of species will the customer attempt to take?</div>
    <div>Insert species valid for product <span data-bind="text: productID"></span> here.
    </div>
    List of species is <span data-bind="text: data.speciesList().length"></span>
    <div class="speciesList" data-bind="if: data.speciesList().length > 0">
        <div class="header">
            <div>Unselected</div>
            <div>Selected</div>
        </div>
        <div data-bind="foreach: data.speciesList">
            <input type="checkbox" data-bind="checked: Chosen"/>
            <label data-bind="text: Name"></label>
        </div>
    </div>
</div>

我的物种-edit.js:

define(['knockout'],
    function (ko) {
        function ProductSpeciesSelectionViewModel(params) {
            var self = this;
            self.productID = params.prodID;

            self.data = params.value;
            self.data.speciesList = ko.observableArray([]);
            self.data.speciesList.push({Name: "Herpdy Derp", Chosen: false});

            console.debug("gonna ask for " + window.applicationBaseUrl + "AdditionalInformation/SpeciesFor/" + self.productID());
            var jqxhr = $.getJSON(window.applicationBaseUrl + "AdditionalInformation/SpeciesFor/" + self.productID())
                .success(function (data, status, xhr) {
                    console.debug(data);
                    self.data.speciesList.push({ Name: "Test", Chosen: false });
                })
                .error(function() { alert("Error in Species Grabber!"); })
                .complete(function() { console.log("Fetch Complete"); });
        }

        return ProductSpeciesSelectionViewModel;
    });

如果您注意到物种编辑视图模型,我实际上并没有使用服务器返回的物种列表。我正在使用“Herpdy Derp”硬件初始化列表,然后当getJSON调用成功时,我正在添加“测试”硬币。但是,自定义元素不显示其中任何一个。它正在接收并显示productID,并且它正在接收长度== 1(应该是2?)的列表,但不呈现列表项的任何属性。这是屏幕上的结果文本。

SW42 - Display Name of Product
Needs Info Type: 0
Needs Info Type: 1
What type of species will the customer attempt to take?
Insert species valid for product SW42 here.
List of species is 1
Unselected
Selected

我很困惑。它将speciesList视为长度为1,但不呈现一个项目。我也很困惑为什么这个列表不是length == 2,因为getJSON调用已经成功了。

这是我第一次使用自定义淘汰赛元素而且我显然没有做对。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

除了Jeff Mercado关于未关闭的parens的评论之外,第二个问题是由于在它上方的console.debug上出现错误,您的JSON调用尚未到达。你还没有定义self.PrivilegeID

修复这两件事后,结果包括两个项目

&#13;
&#13;
function viewModel(){
  var self = this;
  self.infoNeeded = ko.mapping.fromJS([
      {
        "ProductPKUID":10069,
        "ProductID":"SW42",
        "ProductName":"Display Name of Product",
        "Quantity":1,
        "NeededInfo":[
          {"InfoTypeNeeded":0,"InfoGathered":null},
          {"InfoTypeNeeded":1,"InfoGathered":null}
        ]
      }
    ]);
}
    
ko.components.register('species-edit', {
        viewModel: function(params){
            var self = this;
            self.productID = params.prodID;

            self.data = params.value;
            self.data.speciesList = ko.observableArray([]);
            self.data.speciesList.push({Name: "Herpdy Derp", Chosen: false});

            setTimeout(function () {
                self.data.speciesList.push({ Name: "Test 2", Chosen: false });
            }, 2000);
            self.data.speciesList.push({ Name: "Test 1", Chosen: false });
        },
        template: `
        <div>What type of species will the customer attempt to take?</div>
        <div>
          Insert species valid for product <span data-bind="text: productID"></span> here.
        </div>
        List of species is <span data-bind="text: data.speciesList().length"></span>
        <div class="speciesList" data-bind="if: data.speciesList().length > 0">
            <div class="header">
                <div>Unselected</div>
                <div>Selected</div>
            </div>
            <div data-bind="foreach: data.speciesList()">
              <div style="border:1px dashed blue">
                <input type="checkbox" data-bind="checked: Chosen">
                <label data-bind="text: Name"></label>
              </div>
            </div>
        </div>
        `
    });
    

        
 ko.applyBindings(new viewModel());
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>


<div id="additionalInfoNeeded" data-bind="foreach: infoNeeded">
    <span data-bind="text: ProductID"></span> - <span data-bind="text: ProductName"></span>
    <span data-bind="visible: Quantity > 1, text: '(Qty: ' + Quantity + ')'"></span>
    <div data-bind="foreach: NeededInfo">
        <div>
            Needs Info Type: <span data-bind="text: InfoTypeNeeded"></span>
            <div data-bind="if: (InfoTypeNeeded() === 1)"><species-edit params="value: $data, prodID: $parent.ProductID()"></species-edit></div>
        </div>
    </div>
</div>
&#13;
&#13;
&#13;

修改

查看pastebin链接后的主要问题似乎与加载依赖项的方式有关。您在顶部的脚本标记中加载knockout.js,然后您告诉require.js在其路径配置中单独加载knockout。所以任何使用&#39; ko&#39;在索引页面上使用的是不同的敲除实例,而不是在组件中使用ko的任何东西。