不知道如何管理我的数据在observableArray更新

不知道如何管理我的数据在observableArray更新

问题描述:

我刚开始玩KO,因为我想把它带入即将到来的项目。在业余时间,我一直在工作中使用Web服务,这基本上是从数据处理开始,然后做其他事情。所以首先我回来了一个药品名单。好的,让我们添加一个返回结果的计数。好的,让我们用一种模式来填充各个药物的详细信息。好的,让我们编辑一个药物名称。没有真正的韵律或理由,只是想出了东西并与KO一起玩耍。不知道如何管理我的数据在observableArray更新

我现在不知道如何真正管理我的数据,以便随时随地更新。我制作了一张截图,向您介绍我所拥有的内容并说明问题所在。

http://i.imgur.com/5qNWQ.jpg

  1. 通过点击 “是” 按钮,让我的搜索结果。然后我选择 了“优思明28”药物
  2. 我获取该药品的详细视图模式窗口
  3. 我编辑的药品名称,并点击“保存”按钮
  4. 的药品名称为药品的更新模式窗口
  5. 我“欺骗”并更新搜索结果中的药品名称 抓取那部分DOM并用 替换旧药名称的新药名称。

问题是,它没有利用KO的可观察性质...如果我要关闭模式并再次点击“Yasmin 28”药物链接,模式将显示“ Yasmin 28“不是我刚才改变它(”很棒的东西“)。

我不太清楚如何跟踪属性是否在我的observableArray中更改。我制作了两个可观察数据库,一个拥有搜索结果的药物名称列表,另一个拥有该药物的详细信息。我也为目前的药物名称做了观察。

有人可以解释我需要做什么来跟踪我的药物名称吗?我已经包含了下面的代码以及我正在处理的JSON。

<div id="shell"> 
    <button class="load" value="j">j</button> 
    <button class="load" value="k">k</button> 
    <button class="load" value="x">x</button> 
    <button class="load" value="y">y</button> 
    <button class="load" value="z">z</button> 
    <p id="loading"><img src="#{facesContext.externalContext.requestContextPath}/img/spinner.gif"/></p> 

    <h3 data-bind="visible: drugList().length > 0"><span data-bind="text: count" class="count"></span> records returned</h3> 

    <ul data-bind="foreach: drugList"> 
     <li> 
      <span data-bind="text: drugName" class="results_drug_name"></span> 
      <a data-bind="click: $root.showDetails" href="#" class="show">show details</a> 
     </li> 
    </ul> 
</div> 

<!-- start modal: drug details --> 
<div id="dialog" data-bind="jqDialog: {autoOpen: false, title: drugName}"> 
    <p id="dialog_save_message" class="message_success">Changes saved successfully!!!!!!!!</p> 

    <table data-bind="foreach: drugListDetails" class="table" width="100%" cellpadding="0" cellspacing="0" border="1"> 
     <tr> 
      <th scope="row">pdlId</th> 
      <td data-bind="text: pdlId"></td> 
     </tr> 
     <tr> 
      <th scope="row">drugName</th> 
      <td> 
       <span data-bind="text: $root.drugName" class="readonly"></span> 
       <input id="edit_drugname" class="edit_textfield" type="text" value="" size="35" /> 
       <button data-bind="click: $root.editSave" class="edit_buttons save">Save</button> 
       <button data-bind="click: $root.editCancel" class="edit_buttons cancel">Cancel</button> 
       <ul class="detail_actions"> 
        <li><a data-bind="click: $root.edit" href="#" class="edit">edit</a></li> 
       </ul> 
      </td> 
     </tr> 

     <tr> 
      <th scope="row">dosageFormDesc</th> 
      <td data-bind="text: dosageFormDesc"></td> 
     </tr> 
     <tr> 
      <th scope="row">strength</th> 
      <td data-bind="text: strength"></td> 
     </tr> 
     <tr> 
      <th scope="row">activeIngredient</th> 
      <td data-bind="text: activeIngredient"></td> 
     </tr> 
     <tr> 
      <th scope="row">tier</th> 
      <td data-bind="text: tier"></td> 
     </tr> 
     <tr> 
      <th scope="row">ancillaryCharge</th> 
      <td data-bind="text: ancillaryCharge"></td> 
     </tr> 
     <tr> 
      <th scope="row">preauthCode</th> 
      <td data-bind="text: preauthCode"></td> 
     </tr> 
     <tr> 
      <th scope="row">quantityLimit</th> 
      <td data-bind="text: quantityLimit"></td> 
     </tr> 
     <tr> 
      <th scope="row">prefAlternative</th> 
      <td data-bind="text: prefAlternative"></td> 
     </tr> 
     <tr> 
      <th scope="row">specialtyDrug</th> 
      <td data-bind="text: specialtyDrug"></td> 
     </tr> 
     <tr> 
      <th scope="row">partbCob</th> 
      <td data-bind="text: partbCob"></td> 
     </tr> 
     <tr> 
      <th scope="row">drugClassGroupId</th> 
      <td data-bind="text: drugClassGroupId"></td> 
     </tr> 
     <tr> 
      <th scope="row">drugClassId</th> 
      <td data-bind="text: drugClassId"></td> 
     </tr> 
     <tr> 
      <th scope="row">drugClass</th> 
      <td data-bind="text: drugClass"></td> 
     </tr> 
     <tr> 
      <th scope="row">genericInd</th> 
      <td data-bind="text: genericInd"></td> 
     </tr> 
     <tr> 
      <th scope="row">tip</th> 
      <td data-bind="text: tip"></td> 
     </tr> 
    </table> 
</div> 
<!-- end modal: drug details --> 

<script> 
$(function() { 
    $('.load').click(function() { 
     var $letter = $(this).attr('value'); 

     //show spinner 
     $('#loading').show(); 

     //load in drug list data 
     $.getJSON('/PreferredDrugList/service/preferredDrugs/' + $letter, function(data) { 
      //hide spinner 
      $('#loading').hide(); 

      //replace drugList observableArray data 
      //preferredDrugs is an array of objects, each elem is an individual drug 
      myViewModel.drugList(data.preferredDrugs); 

      //replace count observable data 
      myViewModel.count(data.count); 
     });//end getJSON 
    });//end click 

    //setup modal dialog options 
    $('#dialog').dialog({ 
     autoOpen: false, 
     closeOnEscape: true, 
     modal: true, 
     width:850, 
     height:500 
    }); 

});//end ondomready 

//custom binding to initialize a jQuery UI dialog 
ko.bindingHandlers.jqDialog = { 
    init: function(element) { 
     ko.utils.domNodeDisposal.addDisposeCallback(element, function() { 
      $(element).dialog("destroy"); 
     }); 
    }, 
    update: function(element, valueAccessor) { 
     var options = ko.toJS(valueAccessor()); 

     if (options) { 
      $(element).dialog(options); 
     }   
    } 
}; 

var myViewModel = { 
    count:    ko.observable(),  //# of records returned 
    drugList:   ko.observableArray(), //list of drug names - an array of objects 
    drugListDetails: ko.observableArray(), //list of individual drug details 
    drugName:   ko.observable(),  //current drug name 

    //show drug details in modal 
    //func gets passed the current observableArray elem (the individual drug info we clicked on, this is an object) 
    showDetails: function(obj) { 
     //replace current drug name observable data 
     myViewModel.drugName(obj.drugName); 

     //replace drugListDetails observableArray data, otherwise we'll append data to the modal 
     myViewModel.drugListDetails([]); 

     //push individual drug info to details observableArray 
     myViewModel.drugListDetails.push(obj); 

     //show dialog 
     $('#dialog').dialog('open'); 

     return false; 
    }, 

    //edit drug from modal 
    edit: function(obj) { 
     var $edit   = $('#dialog').find('td .edit'), 
      $currentTD = $edit.closest('td'); 

     $currentTD.addClass('editing'); 
     $currentTD.find('.readonly').hide(); 
     $currentTD.find('.edit_textfield').show().select(); 
     $currentTD.find('.edit_buttons').show(); 

     return false; 
    }, 

    //save an edit 
    editSave: function(obj) { 
     alert('TODO save back to the server'); 

     var $saveBtn = $('#dialog').find('td .save'), 
      $currentTD = $saveBtn.closest('td'), 
      newDrugName = $('#edit_drugname').val(), 
      $dialog_save_message = $('#dialog_save_message'); 

     //save new drug name to observable 
     myViewModel.drugName(newDrugName); 

     $currentTD.removeClass('editing'); 
     $currentTD.find('.readonly').show(); 
     $currentTD.find('.edit_textfield').hide(); 
     $currentTD.find('.edit_buttons').hide(); 

     $dialog_save_message.slideDown('slow', function() { 
      //animation complete 
      setTimeout(function() { 
       $dialog_save_message.slideUp(); 
      }, 3000); 
     }); 

     //cheat and update search results list with new drug name 
     $('.results_drug_name').each(function(index, elem) { 
      var $text = $(this).text(); 

      if ($text === obj.drugName) { 
       $(this).text(newDrugName).addClass('edited'); 
      } 
     }); 
    }, 

    //cancel an edit 
    editCancel: function(obj) { 
     var $cancelBtn  = $('#dialog').find('td .cancel'), 
      $currentTD = $cancelBtn.closest('td'); 

     $currentTD.removeClass('editing'); 
     $currentTD.find('.readonly').show(); 
     $currentTD.find('.edit_textfield').hide(); 
     $currentTD.find('.edit_buttons').hide(); 
    } 
}; 

ko.applyBindings(myViewModel); 

<!--what's returned from the web service--> 
<pre> 
{ 
    "preferredDrugs": [(8) 
     { 
      "pdlId": 8090, 
      "drugName": "y-cof-dmx", 
      "dosageFormDesc": "Liquid", 
      "strength": "4MG/5ML; 15MG/5ML; 7.5MG/5ML", 
      "activeIngredient": "BROMPHENIRAMINE MALEATE; DEXTROMETHORPHAN HYDROBROMIDE; PHENYLEPHRINE HYDROCHLORIDE", 
      "tier": "OTC", 
      "ancillaryCharge": "NA", 
      "preauthCode": " ", 
      "quantityLimit": " ", 
      "prefAlternative": null, 
      "specialtyDrug": " ", 
      "partbCob": " ", 
      "drugClassGroupId": 74, 
      "drugClassId": 152, 
      "drugClass": "Respiratory Tract Agents » Antitussives", 
      "genericInd": "1", 
      "tip": " " 
     },- 
     { 
      "pdlId": 13417, 
      "drugName": "YASMIN 28", 
      "dosageFormDesc": "Tablet", 
      "strength": "3MG; 0.03MG", 
      "activeIngredient": "DROSPIRENONE; ETHINYL ESTRADIOL", 
      "tier": "3", 
      "ancillaryCharge": "AC", 
      "preauthCode": " ", 
      "quantityLimit": "28.0 tabs each 28 days", 
      "prefAlternative": "ethinyl estradiol/drospirenone", 
      "specialtyDrug": " ", 
      "partbCob": " ", 
      "drugClassGroupId": 3, 
      "drugClassId": 200, 
      "drugClass": "Hormones and Synthetic Substitutes » Contraceptives", 
      "genericInd": "0", 
      "tip": " " 
     },- 
     { 
      "pdlId": 24765, 
      "drugName": "YAZ", 
      "dosageFormDesc": "Tablet", 
      "strength": "3MG; 0.02MG", 
      "activeIngredient": "DROSPIRENONE; ETHINYL ESTRADIOL", 
      "tier": "3", 
      "ancillaryCharge": "AC", 
      "preauthCode": " ", 
      "quantityLimit": "28.0 tabs each 28 days", 
      "prefAlternative": "ethinyl estradiol/drospirenone", 
      "specialtyDrug": " ", 
      "partbCob": " ", 
      "drugClassGroupId": 3, 
      "drugClassId": 200, 
      "drugClass": "Hormones and Synthetic Substitutes » Contraceptives", 
      "genericInd": "0", 
      "tip": " " 
     },- 
     { 
      "pdlId": 2252, 
      "drugName": "YERVOY", 
      "dosageFormDesc": "Solution", 
      "strength": "50MG/10ML", 
      "activeIngredient": "IPILIMUMAB", 
      "tier": "NC", 
      "ancillaryCharge": "NA", 
      "preauthCode": " ", 
      "quantityLimit": " ", 
      "prefAlternative": null, 
      "specialtyDrug": " ", 
      "partbCob": " ", 
      "drugClassGroupId": 115, 
      "drugClassId": 1, 
      "drugClass": "Antineoplastic Agents", 
      "genericInd": "0", 
      "tip": " " 
     },- 
     { 
      "pdlId": 20993, 
      "drugName": "YERVOY", 
      "dosageFormDesc": "Solution", 
      "strength": "200MG/40ML", 
      "activeIngredient": "IPILIMUMAB", 
      "tier": "NC", 
      "ancillaryCharge": "NA", 
      "preauthCode": " ", 
      "quantityLimit": " ", 
      "prefAlternative": null, 
      "specialtyDrug": " ", 
      "partbCob": " ", 
      "drugClassGroupId": 115, 
      "drugClassId": 1, 
      "drugClass": "Antineoplastic Agents", 
      "genericInd": "0", 
      "tip": " " 
     },- 
     { 
      "pdlId": 564, 
      "drugName": "YF-VAX", 
      "dosageFormDesc": "Injection", 
      "strength": "0", 
      "activeIngredient": "YELLOW FEVER VACCINE", 
      "tier": "NC", 
      "ancillaryCharge": "NA", 
      "preauthCode": " ", 
      "quantityLimit": " ", 
      "prefAlternative": null, 
      "specialtyDrug": " ", 
      "partbCob": " ", 
      "drugClassGroupId": 79, 
      "drugClassId": 284, 
      "drugClass": "Serums, Toxoids and Vaccines » Vaccines", 
      "genericInd": "0", 
      "tip": " " 
     },- 
     { 
      "pdlId": 8910, 
      "drugName": "yodefan-nf chest congestion", 
      "dosageFormDesc": "Liquid", 
      "strength": "200MG/5ML", 
      "activeIngredient": "GUAIFENESIN", 
      "tier": "OTC", 
      "ancillaryCharge": "NA", 
      "preauthCode": " ", 
      "quantityLimit": " ", 
      "prefAlternative": null, 
      "specialtyDrug": " ", 
      "partbCob": " ", 
      "drugClassGroupId": 84, 
      "drugClassId": 155, 
      "drugClass": "Respiratory Tract Agents » Expectorants", 
      "genericInd": "1", 
      "tip": " " 
     },- 
     { 
      "pdlId": 13101, 
      "drugName": "YODOXIN", 
      "dosageFormDesc": "Tablet", 
      "strength": "650MG", 
      "activeIngredient": "IODOQUINOL", 
      "tier": "3", 
      "ancillaryCharge": "NA", 
      "preauthCode": " ", 
      "quantityLimit": " ", 
      "prefAlternative": "iodoquinol", 
      "specialtyDrug": " ", 
      "partbCob": " ", 
      "drugClassGroupId": 164, 
      "drugClassId": 277, 
      "drugClass": "Anti-infective Agents » Antiprotozoals", 
      "genericInd": "0", 
      "tip": " " 
     }- 
    ],- 
    "count": 8 
} 
</pre> 

</script> 
+0

为什么你使用两种不同的药物清单?为什么不为两者使用相同的列表? –

+0

这就是我无法弄清的 - 如何使用一个observableArray?当我从服务器加载JSON数据时,我正在使用:myViewModel.drugList(data.preferredDrugs); (一个用foreach迭代的对象数组)我如何使它工作:myViewModel.drugList(data);这是我的JSON结构中的更高层次?我似乎无法钻入preferredDrugs数组。 –

首先,取出drugListDetails阵列,因为它通过保持你的数据的重复引起的混乱。

,用ko.mapping.fromJSko.mapping.toJSdata.preferredDrugs映射,并从可观察到的阵列。这将允许knockout跟踪阵列中每个元素的GUI更改。这些文件可以找到here

您也可以手动进行映射,如果你不希望使用mapping插件。

,新showDetails元素在你的data.preferredDrugs阵列,默认添加到每个条目false。这将在下一步中用于确定是否应该显示对话框。该showDetails元素将需要切换时,现有的$root.showDetails被调用。

第四,修改对话div使用drugList阵列及其visible值绑定到每个药物元件的showDetails值。这将创建多个隐藏的对话框,因此您可能需要更改每个对话框的id值。

+0

现在查看映射插件。我可以使用静态数据,但从服务器加载json时似乎不起作用。感谢那个插件的头像,看起来像我需要的。 –