2

タスクを達成するためにノックアウト js を使用しています。私のモデルは次のようなものです:

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>

問題は、あるクラスで税サービスに ServiceRate を提供すると、他のすべてのクラスで同じサービスのテキスト フィールドに更新されることです。それに関するどんな助けも素晴らしいでしょう。

4

1 に答える 1

6

コードにはいくつかの問題があります。

  1. まず、主に化粧品です。レイアウトにテーブルを使用しています。表形式のデータが本当に必要な場合にのみ使用してください。ほとんどの場合、Divまたはリストの方がはるかに優れており、何かをレイアウトする必要がある場合は、cssマージンを使用できます。

  2. さまざまなオブジェクトスキームを混ぜ合わせています。

    • 1つは、オブジェクトリテラルを返すことです。

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

      newこのスキーマは、演算子で呼び出すことができますが、呼び出すべきではありません。

    • もう1つはプロトタイプベースです。

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

      newこのスキーマは、オペレーターで呼び出す必要があります。

    1つのスキーマに固執するのが最も簡単です。ノックアウトを使用すると、後者の方が使いやすい場合があります。

  3. すべてのプロパティにオブザーバブルを使用しているわけではありません。一部のプロパティにオブザーバブルを使用し、他のプロパティには使用しないのは少し混乱します。各プロパティを確認するには、ソースコードに戻る必要があります。

  4. オブジェクトモデルでは、オブジェクトの再利用は考慮されていません。それぞれServiceLevelRateに同じオブジェクトを渡すので、1つを更新すると、他のすべてのオブジェクトもTaxService同じように更新されます。TaxServiceTaxClass

    これに対する簡単な解決策の1つは、更新が必要なフィールドをマッピングオブジェクトに除外することです。

    // 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-bindingを使用してレートをバインドできます。ワイドレートのサブスクリプションでは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フィルタリングできます。TaxServiceTaxClass

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);
}
于 2012-12-25T01:52:57.167 に答える