Search code examples
javascriptvalidationknockout.jsknockout-mvc

Validating Duplicate Data Between ObservableArrays


I have an observable array (populated via ajax) that on validation, cannot have a select value the same on any 2 or more observables within the array.

<div id="AttrValidationDiv"></div>
    <table>    
    <!-- ko foreach: AttrsViewModels -->
         <tr>
            <td>
              <select data-bind="options:$root.optionsViewModel, optionsText:'ProductName', optionsValue:'ProductId',value:ServiceGroup, optionsCaption:'Select'"></select>
           </td>
          </tr>
        <!-- /ko -->
    </table>

Is there a way to accomplish this in adding/removing from the validation div in real time?


Solution

  • You can accomplish this with a computed function that checks each option against the selected options in your AttrsViewModels. The computed will automatically recalculate whenever a selected option changes because they're observables, and the div text will be updated if bound to the computed function.

    function viewModel(){
      var self = this;
      
      this.optionsViewModel = [
        { ProductId: 1, ProductName: 'product 1' },
        { ProductId: 2, ProductName: 'product 2' },
        { ProductId: 3, ProductName: 'product 3' }
      ];
      
      this.AttrsViewModels = ko.observableArray([
        { ServiceGroup: ko.observable() },
        { ServiceGroup: ko.observable() },
        { ServiceGroup: ko.observable() }
      ]);
      
      this.validations = ko.computed(function(){
        for(var i=0; i<self.optionsViewModel.length; i++){
        	var option = self.optionsViewModel[i];
            var matches = self.AttrsViewModels().filter(function(item){
                return item.ServiceGroup() === option.ProductId;
            });
            if(matches.length >= 2){
          	    return option.ProductName + ' is selected more than once';
            }
        }
        return '';
      });
    }
        
    ko.applyBindings(new viewModel());
    <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>
    
    <div id="AttrValidationDiv">
      <span data-bind="text: validations"></span>
    </div>
    <table>    
        <tbody>
        <!--ko foreach: AttrsViewModels-->
         <tr>
            <td>
              <select data-bind="options:$root.optionsViewModel, optionsText:'ProductName', optionsValue:'ProductId',value:ServiceGroup, optionsCaption:'Select'"></select>
           </td>
        </tr>
        <!--/ko-->
        </tbody>
    </table>