2017-01-11 17 views
0

ノックアウトコードとバインディングがたくさんあるフィドルがあります。私はobservablearray内の項目をチェックするバインディングを1つ持っており、入力した値に関係なく常に真を返すようです。最後の行の最後の入力にカーソルを置き、タブアウトします。新しい行が追加されます。次に、最初の入力に値を入力し、タブアウトします。既存のobservable配列をチェックし、存在する場合はtrueまたはfalseを返すことになっています。フィドル:https://jsfiddle.net/mf1wona9/6/ノックアウト配列は期待通りに働いていません

HTML:

<table class="table table-bordered table-striped" id="brochureItems"> 
<thead> 
    <tr> 
     <th> 
      Item No 
     </th> 
     <th> 
      Bro Code 
     </th> 
     <th width="36%"> 
      Desc 
     </th> 
     <th width="15%"> 
      Retail 
     </th> 
     <th> 
      Prize Cnt 
     </th> 
     <th> 
      Order 
     </th> 
     <th> 
      Remove 
     </th> 
    </tr> 
</thead> 
<tbody data-bind="foreach: items"> 
    <tr> 
     <td> 
      <div data-bind="if: ($index() === $parent.items().length-1)"><input data-bind="value: itemNo, hasFocus: $parent.invalidItem(), selected: $parent.invalidItem(), event: { blur: $parent.checkItemNo }, attr: { name: 'brochureitems[' + $index() + '].itemNo', id: 'brochureItems_' + $index() + '__itemNo' }, validationOptions: { errorElementClass: 'input-validation-error' }" class="form-control item-id" /></div> 
      <div data-bind="ifnot: ($index() === $parent.items().length-1)"><input data-bind="value: itemNo, attr: { name: 'brochureitems[' + $index() + '].itemNo', id: 'brochureItems_' + $index() + '__itemNo' }, validationOptions: { errorElementClass: 'input-validation-error' }" class="form-control item-ID" readonly="readonly" tabindex="-1" /></div> 
     </td> 
     <td> 
      <div data-bind="if: (brocCode.length < 1)"> 
       <input data-bind="value: brocCode, insertPress: $index, attr: { name: 'brochureitems[' + $index() + '].brocCode', id: 'brochureItems_' + $index() + '__brocCode' }, validationOptions: { errorElementClass: 'input-validation-error' }" class="form-control" /> 
      </div> 
      <div data-bind="if: (brocCode.length > 0)"> 
       <input data-bind="value: brocCode, insertPress: $index, attr: { name: 'brochureitems[' + $index() + '].brocCode', id: 'brochureItems_' + $index() + '__brocCode' }, validationOptions: { errorElementClass: 'input-validation-error' }" class="form-control" readonly="readonly" tabindex="-1" /> 
      </div> 
     </td> 
     <td class="item-desc"> 
      <input data-bind="value: itemDesc, attr: { name: 'brochureitems[' + $index() + '].itemDesc', id: 'brochureItems_' + $index() + '__itemDesc' }, validationOptions: { errorElementClass: 'input-validation-error' }" class="form-control" readonly="readonly" tabindex="-1" /> 
     </td> 
     <td class="item-retail"> 
      <div class="input-group"> 
       <div class="input-group-addon">$</div> 
       <div data-bind="if: ($index() === ($parent.items().length - 1))"><input data-bind="value: retail, valueUpdate: 'afterkeydown', attr: { name: 'brochureitems[' + $index() + '].retail', id: 'brochureItems_' + $index() + '__retail' }, validationOptions: { errorElementClass: 'input-validation-error' }, style: { backgroundColor: retail == 0 ? '#FFFCCE' : '#ffffff'}" class="form-control" /></div> 
       <div data-bind="if: ($index() < ($parent.items().length - 1))"><input data-bind="value: retail, valueUpdate: 'afterkeydown', money: retail, attr: { name: 'brochureitems[' + $index() + '].retail', id: 'brochureItems_' + $index() + '__retail' }, validationOptions: { errorElementClass: 'input-validation-error' }, style: { backgroundColor: retail == 0 ? '#FFFCCE' : '#ffffff'}" class="form-control" readonly="readonly" tabindex="-1" /></div> 
      </div> 
     </td> 
     <td> 
      <div><input data-bind="value: prizeNum, valueUpdate: 'afterkeydown', attr: { name: 'brochureitems[' + $index() + '].prizeNum', id: 'brochureItems_' + $index() + '__prizeNum' }, validationOptions: { errorElementClass: 'input-validation-error' }, style: { backgroundColor: prizeNum == 0 ? '#FFFCCE' : '#ffffff'}" class="form-control" /></div> 
     </td> 
     <td> 
      <div data-bind="if: ($index() === ($parent.items().length - 1))"><input data-bind="value: itemOrder, valueUpdate: 'afterkeydown', enterPress: 'addRow', attr: { name: 'brochureitems[' + $index() + '].itemOrder', id: 'brochureItems_' + $index() + '__itemOrder' }, validationOptions: { errorElementClass: 'input-validation-error' }, style: { backgroundColor: itemOrder == 0 ? '#FFFCCE' : '#ffffff'}" class="form-control" /></div> 
      <div data-bind="if: ($index() < ($parent.items().length - 1))"><input data-bind="value: itemOrder, valueUpdate: 'afterkeydown', attr: { name: 'brochureitems[' + $index() + '].itemOrder', id: 'brochureItems_' + $index() + '__itemOrder' }, validationOptions: { errorElementClass: 'input-validation-error' }, style: { backgroundColor: itemOrder == 0 ? '#FFFCCE' : '#ffffff'}" class="form-control" /></div> 
     </td> 
     <td class="remove"><span class="glyphicon glyphicon-remove removeRow" data-bind="click: $parent.removeItem"></span></td> 

    </tr> 
</tbody> 

ノックアウト:

var listOfItems; 

ko.validation.rules.pattern.message = 'Invalid.'; 
    ko.validation.init({ 
     registerExtenders: true, 
     messagesOnModified: true, 
     insertMessages: true, 
     parseInputAttributes: true, 
     messageTemplate: null, 
     decorateInputElement: true, 
    }, true); 

    (function(){ 

     var toMoney = function(num){ 
      if(num != null && num != "") { 
       num = parseFloat(num); 
       return (num.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, '$1,')); 
      } else { 
       return ""; 
      } 
     }; 

     var handler = function(element, valueAccessor, allBindings){ 
      var $el = $(element); 
      var method; 

      // Gives us the real value if it is a computed observable or not 
      var valueUnwrapped = ko.unwrap(valueAccessor()); 

      if($el.is(':input')){ 
       method = 'val'; 
      } else { 
       method = 'text'; 
      } 
      return $el[method](toMoney(valueUnwrapped)); 
     }; 

     ko.bindingHandlers.money = { 
      update: handler 
     }; 
    })(); 

    var itemModel = function (data) { 
     var self = this; 
     self.invalidItem = ko.observable(true); 
     self.itemNo = ko.observable(data ? data.itemNo : '').extend({ 
      required: { 
       params: true, 
       message: "Item no. required." 
      } 
     }); 
     self.brocCode = ko.observable(data ? data.brocCode : '').extend({ 
      required: { 
       params: true, 
       message: "Bro code required." 
      } 
     }); 
     self.itemDesc = ko.observable(data ? data.itemDesc : '').extend({ 
      required: { 
       params: true, 
       message: "Item desc required." 
      } 
     }); 
     self.retail = ko.observable(data ? data.retail : '').extend({ 
      required: { 
       params: true, 
       message: "Retail required." 
      } 
     }) 
     .extend({numeric: 2}); 
     self.prizeNum = ko.observable(data ? data.prizeNum : '').extend({ 
      required: { 
       params: true, 
       message: "Prize num required." 
      } 
     }); 
     self.itemOrder = ko.observable(data ? data.itemOrder : '').extend({ 
      required: { 
       params: true, 
       message: "Item order required." 
      } 
     }); 
    } 

    var itemsModel = function(items) { 
     var self = this; 
     self.items = ko.mapping.fromJSON(items); 

     self.invalidItem = ko.observable(true); 

     self.checkItemNo = function(data) { 
      console.log("lost focus - " + self.invalidItem()); 
      var itemNo = $.trim(data.itemNo()); 
      console.log(itemNo); 
      if (itemNo != "") { 
       var item = ""; 
       item = "Fusion"; 
       console.log(item); 
       if(item != "") { 
        var match = ko.utils.arrayFirst(self.items(), function(newItem) { 
         return itemNo === newItem.itemNo(); 
        }).itemNo(); 
        console.log("match: " + match); 
        if (!match) { 
         data.itemDesc(item); 
        } else { // item already entered 
         console.log("item already entered"); 
         data.invalidItem(true); 
         setTimeout(function() { data.invalidItem(true); }, 1); 
         //data.itemDesc(""); 
        } 
       } else { // invalid item # 
        console.log("invalid item"); 
        data.invalidItem(true); 
        setTimeout(function() { data.invalidItem(true); }, 1); 
        data.itemDesc(""); 
       } 
      } 
     } 

     self.submit = function() { 
      //self.showErrors(true); 
      if (viewModel.errors().length === 0) { 
       console.log('Thank you.'); 
       $("#brochureForm").submit(); 
      } 
      else { 
       console.log('Please check your submission.'); 
       viewModel.errors.showAllMessages(); 
       $(".input-validation-error").first().focus(); 
      } 
     } 

     self.addLine = function() { 
      var iModel = new itemModel(); 
      iModel.invalidItem(true); 
      self.invalidItem(true); 
      console.log("adding new line; it is: " + self.invalidItem()); 
      self.items.push(iModel); 
      //setTimeout(function() { self.invalidItem(true); }, 1); 
     }; 

     self.insertLine = function(index) { 
      self.items.splice(index, 0, new itemModel()); 
     }; 

     self.removeItem = function(item) { 
      self.items.remove(item); 
     }; 

     self.errors = ko.validation.group(self.items, { deep: true, live: true }); 

     self.validate = function() { 
      self.errors.showAllMessages(); 
     } 
    }; 

    var profitCode = function(code, desc, name) { 
     this.code = code; 
     this.desc = desc; 
     this.name = name; 
    }; 

    var codeModel = function(codes) { 
     var self = this; 
     self.availableProfitCodes = ko.observableArray([]) 
     self.codes = ko.observableArray(codes); 
    } 

    var profitItemsModel = function(items) { 
     var self = this; 
     self.items = ko.observableArray(items); 
    } 

    var combined = (function() { 
     function combinedVM() { 
      this.codes = ko.observable(codeModel); 
      this.items = ko.observable(profitItemsModel); 
      this.availableProfitCodes = codeModel.availableProfitCodes; 
     } 
     return combinedVM; 
    })(); 

    ko.bindingHandlers.enterPress = { 
     init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
      var allBindings = allBindingsAccessor(); 
      element.addEventListener('keydown', function (event) { 
       var keyCode = (event.which ? event.which : event.keyCode); 
       if (keyCode === 13 || (!event.shiftKey && keyCode === 9)) { 
        event.preventDefault(); 
        //bindingContext.$root.invalidItem(false); 
        bindingContext.$root.addLine(); 
        return false; 
       } 
       return true; 
      }); 
     } 
    }; 

     ko.bindingHandlers.insertPress = { 
      init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
       var allBindings = allBindingsAccessor(); 
       element.addEventListener('keydown', function (event) { 
        var keyCode = (event.which ? event.which : event.keyCode); 
        if (keyCode === 45) { 
         event.preventDefault(); 
         bindingContext.$root.insertLine(ko.unwrap(valueAccessor())); 
         return false; 
        } 
        return true; 
       }); 
      } 
     }; 

     ko.bindingHandlers.selected = { 
      update: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { 
       var selected = ko.utils.unwrapObservable(valueAccessor()); 
       if (selected) element.select(); 
      } 
     };   

     function GetItems() { 
    var itemsJSON = '[{"brochureId":1,"itemNo":"1000","brocCode":"1000","itemDesc":"Bicycle","retail":13.5, "prizeNum":1, "itemOrder":1},{"brochureId":1,"itemNo":"1100","brocCode":"1100","itemDesc":"Front Wheel","retail":35, "prizeNum":2, "itemOrder":2},{"brochureId":1,"itemNo":"1120","brocCode":"1120","itemDesc":"Spokes","retail":12.5, "prizeNum":3, "itemOrder":3},{"brochureId":1,"itemNo":"1150","brocCode":"1150","itemDesc":"Front Hub","retail":5, "prizeNum":4, "itemOrder":4},{"brochureId":1,"itemNo":"1151","brocCode":"1151","itemDesc":"Axle Front Wheel","retail":14, "prizeNum":5, "itemOrder":5},{"brochureId":1,"itemNo":"120","brocCode":"120","itemDesc":"Loudspeaker, Black, 120W","retail":12.5, "prizeNum":6, "itemOrder":6},{"brochureId":1,"itemNo":"125","brocCode":"125","itemDesc":"Socket Back","retail":10, "prizeNum":7, "itemOrder":7}]'; 
    var viewModel = new itemsModel(itemsJSON); 
    ko.applyBindings(viewModel, $("#brochureItems")[0]); 
    } 

$(document).ready(function() { 
    GetItems(); 
}); 

答えて

1

新しいアイテムが観測アレイの一部です。それはいくつか項目と一致するかどうかを確認するには、あなたが自分自身にそれを比較していないことを確認する必要があります

var match = ko.utils.arrayFirst(self.items(), function(newItem) { 
    return data !== newItem && itemNo === newItem.itemNo(); 
}); 
+0

パーフェクト、感謝を! – dmikester1

関連する問題