2012-12-21 59 views
2

我正在使用擊倒js來獲得任務。我的模型是這樣的:Knockout JS foreach嵌套,所有領域的值更新

var ServiceLevelRates = function(data, availableClasses) { 
return { 
    TaxTypeID: ko.observable(data.Key), 
    TaxTypeName: ko.observable(data.Name), 
    ExtendedTaxTypeName: data.Name.replace(/\s+/g, ''), 
    ApplyAfter: ko.observable(-1), 
    TaxClasses: ko.observableArray(availableClasses) 
}; 
}; 

var TaxClass = function(data, availableServices) { 
return { 
    ServiceClassID: data.ServiceClassID, 
    ServiceClassName: ko.observable(data.ServiceClassName), 
    TaxServices: ko.observableArray(availableServices) 
}; 
}; 

var TaxService = function(data) { 
return { 
    ServiceID: ko.observable(data.ServiceID), 
    ServiceName: ko.observable(data.ServiceName), 
    ServiceRate: ko.observable(data.ServiceRate > 0 ? data.ServiceRate : "").extend({ numeric: 2 }) 
}; 
}; 

和我的HTML是這樣的:

<tbody data-bind="foreach: ServiceLevelRates"> 
        <tr> 
         <td style="width:100%;"> 
          <table width="100%"> 
           <tr> 
            <td style="width:2%;"> 
             <img src="../../Images/del_up.gif" onclick="HideMyChilds(this);" /> 
            </td> 
            <td data-bind="text: TaxTypeName"> 

            </td> 
           </tr> 
           <tr> 
            <td></td> 
            <td> 
             <table width="100%"> 
              <tr> 
               <td style="width:20%;"> 
                <label id="lblApplyAfter" myId="lblApplyAfter" runat="server">Apply After</label> 
               </td> 
               <td></td> 
              </tr> 
              <tr> 
               <td> 
                <select id="sltApplyAfter" SkinID="drpFields" name="sltApplyAfter" runat="server" myId="sltApplyAfter"> 
                 <option value="-1">Charge</option> 
                </select> 
               </td> 
               <td> 
                <input type="checkbox" />Apply for All Services<input type="text" onkeypress="ValidateDecimalValue(event,this)"; onblur="ApplyForAllServices(this);" data-bind="attr: { 'class': ExtendedTaxTypeName }" /> % 
               </td> 
              </tr> 
              <tr> 
               <td colspan="2"> 
                <table width="100%"> 
                 <tbody data-bind="foreach: TaxClasses"> 
                  <tr> 
                   <td style="width:2%;"> 
                    <img src="../../Images/del_up.gif" onclick="HideMyChilds(this);" /> 
                   </td> 
                   <td style="width:100%;" class="tdRepeaterHeaderBG" data-bind="text: ServiceClassName"> 

                   </td> 
                  </tr> 
                  <tr> 
                   <td></td> 
                   <td> 
                    <table width="100%"> 
                     <thead> 
                      <tr> 
                       <td style="width:1%;"> 
                       <td style="width:24%;" class="tdRepeaterHeaderBG">Service Name</td> 
                       <td style="width:75%;" class="tdRepeaterHeaderBG">Amount</td> 
                      </tr> 
                     </thead> 
                     <tbody data-bind="foreach: TaxServices"> 
                      <tr> 
                       <td style="width:1%;"> 
                       <td style="width:24%;" data-bind="text: ServiceName"></td> 
                       <td style="width:75%;"> 
                        <input type="text" data-bind="value: ServiceRate, attr: { 'class': $parents[1].ExtendedTaxTypeName, 'id': $parents[1].ExtendedTaxTypeName + ServiceID }" />% 
                       </td> 
                      </tr> 
                      <tr> 
                       <td></td> 
                       <td colspan="2"> 
                        <div style="font-size: 11px; width:98%;height:5px; border-top: 1px dotted gray;"> </div> 
                       </td> 
                      </tr> 
                     </tbody> 
                    </table> 
                   </td> 
                  </tr> 
                 </tbody> 
                </table> 
               </td> 
              </tr> 
             </table> 
            </td> 
           </tr> 
          </table> 
         </td> 
        </tr> 
       </tbody> 

問題是,當我在一個類中的taxservice提供ServiceRate,將其更新到所有相同的服務的文本字段其他類。任何幫助它都會很棒。

+0

也許你可以嘗試在jsFiddle中重現這個?這是一個開始:http://jsfiddle.net/rniemeyer/T89GH/ –

+0

你可以告訴我們JavaScript在哪裏創建你的viewmodels然後綁定到頁面? – CodeThug

+0

@RPNiemeyer非常感謝這個開始,但我無法在那裏產生:(但是如果你可以幫助我解決另一個問題,如果你檢查jsFiddle,我們有一個文本框說'申請所有服務',在它的模糊我調用一個方法'ApplyForAllServices',我已經在jsFiddle中複製,與我本地此方法複製子文本框中的值,但KO視圖模型不會更新,請你幫我出來我是新來的KO,對不起,如果問幼稚的東西,請提前致謝 –

回答

6

您的代碼有幾個問題。

  1. 首先,主要是化妝品。您正在使用表格進行佈局。只有在您真正需要表格數據時才能使用它們。在大多數情況下,Div或列表要好得多,如果你需要佈局某些東西,你可以使用CSS邊界。

  2. 你在混合和混合不同的對象方案。

    • 一個是返回一個對象字面:

      function Foo() { 
          return { 
           Property: ko.observable(), 
          } 
      } 
      

      這種模式可以,但不應該被用new操作者調用。

    • 另一種是基於原型:

      function Foo() { 
          var self = this; 
      
          self.Property = ko.observable(); 
      } 
      

      這個模式必須與new運算符來調用。

    堅持一種模式是最容易的。在淘汰賽中,後者在某些情況下更易於使用。

  3. 您並未對所有屬性使用observables。對某些屬性使用observables而不是其他屬性有些困惑。你必須回到源代碼來確認每個屬性。

  4. 您的對象模型不考慮對象重用。您正在向每個ServiceLevelRate傳遞相同的對象,因此當您更新一個TaxService時,所有其他TaxClass中的相同TaxService也將被更新。

    對此,一個簡單的解決方案是將需要更新的字段分解爲映射對象。

    // This part is constructed once, based on server data. 
    function TaxService(data) { 
        var self = this; 
    
        self.ServiceID = ko.observable(data.ServiceID); 
        self.ServiceName = ko.observable(data.ServiceName); 
    } 
    
    // This part is constructed for each TaxClassMapping 
    function TaxServiceMapping(svc) { 
        var self = this; 
    
        self.TaxService = ko.observable(svc); 
        self.ServiceRate = ko.observable(""); 
    } 
    
  5. 最後;要根據複選框有條件地更新費率,可以將其與checked綁定綁定。在訂購ServiceLevelRate範圍內的費率時,您只需檢查是否選中了該複選框,然後再繼續更新其他字段。

    self.ApplyForAll.subscribe(function (newValue) { 
        if (self.ApplyForAllCheckBox()) { 
         ko.utils.arrayForEach(self.Classes(), function (clsMapping) { 
          ko.utils.arrayForEach(clsMapping.ClassServices(), function (svcMapping) { 
           svcMapping.ServiceRate(newValue); 
          }); 
         }); 
        } 
    }); 
    

這裏是一個更新的小提琴:

http://jsfiddle.net/MizardX/V8DTj/

我按比例縮小的模型,關鍵部位,使它們更容易使用。


爲了使TaxServices僅對某些TaxClasses顯示,你可以過濾要包括每個TaxClassTaxService -objects。

function TaxClassMapping(taxClass, availableServices) { 
    var self = this; 

    self.TaxClass = ko.observable(taxClass); 

    var classID = taxClass.ServiceClassID(); 
    var filtered = ko.utils.arrayFilter(availableServices, function (svc) { 
     // svc.ServiceClassID is a new property in TaxService 
     return svc.ServiceClassID() === classID; 
    }); 
    var mapped = ko.utils.arrayMap(filtered, function (svc) { 
     return new TaxServiceMapping(svc); 
    }); 
    self.ClassServices = ko.observableArray(mapped); 
} 
+0

馬庫斯!對於詳細分析和提示以及解決方案非常感謝,對於遲到回覆感到抱歉。我現在要去處理你的指導方針。 –

+0

非常感謝Markus,它效果很好。 –

+0

!如果我在otaxServices數組中引入ServiceClassID,並且希望服務出現在相應的類下,那麼我必須遵循什麼方法? –