0
votes

it's a little complicated for me to explain my issue. Basically i have viewmodel that i bind to a view, in that viewmodel i have a observable object that i bind to the view with a "with" tag from knockout. This property is called SelectedItem, because represent the item that you select from a grid. The data in this grid are plain objects, so i have to convert to obervable objects, in order to bind it to this view.

the issue comes when i have to bind the second object, the application just doesn't work.

i've created a fiddle for this issue. http://jsfiddle.net/q7q0f7oq/11/

Natal.applyBindings(myViewModel).done(function() {
    Natal.Validation.init('#editForm');
});

this is a library that i use at my work, that encapsulate Knockoutjs and other libraries.

if you push the new button, then the save button (without completing anything) it will trigger the validation. then you close the window with the cancel button, and open the window again, pushing the new button again. when you try to execute the validation again, it will fail.

now, i could find that this is not the proper way to do this binding with Knockout, but i don't know what could i do to fix this. the only this that i come around with this, is to recycle the object, and don't create a new one.

1

1 Answers

1
votes

It looks like you are unfamiliar with how Knockout works. You cannot mix jQuery and Knockout the way you have and get good results. The Knockout way is that you control the view from your viewmodel. You don't reach around and fiddle with the DOM directly. If you feel like you have to fiddle with the DOM, ask yourself "Why am I not doing this through the model?"

Natal's validation looks to be unfriendly to Knockout, since it apparently wants to work directly on the DOM. There's not much you can do about that.

I found a bindingHandler for Bootstrap modal for you to use, so now it's controlled by modalIsOpen observable. I made observables to bind the other form inputs to. I put the validation and reset functions inside the viewmodel instead of having them be global. I used bindings to hook up click events.

It seemed pointless to me to create a new observable for codigo every time the form is reset; instead, I just changed its value. Maybe that made the difference. I don't know. It has no problem running its validation now.

ko.bindingHandlers.modal = {
  init: function(element, valueAccessor) {
    $(element).modal({
      show: false
    });

    var value = valueAccessor();
    if (ko.isObservable(value)) {
      $(element).on('hide.bs.modal', function() {
        value(false);
      });
    }
    ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
      $(element).modal("destroy");
    });

  },
  update: function(element, valueAccessor) {
    var value = valueAccessor();
    if (ko.utils.unwrapObservable(value)) {
      $(element).modal('show');
    } else {
      $(element).modal('hide');
    }
  }
};

$(document).ready(function() {

  // Cuando se oculta el modal, reseteo la validación para que cuando vuelva a abrir no esten las marcas de validación

  // Definimos el viewmodel del ejemplo
  var ViewModel = function() {
    var self = this;
    var form = "#editForm";

    function resetForm() {
      Natal.Validation.reset(form);
      var item = self.selectedItem();
      item.codigo(0);
      item.descripcion('');
      item.comments('');
    }

    self.modalIsOpen = ko.observable(false);
    self.openModal = function() {
      self.modalIsOpen(true);
    };
    self.closeModal = function() {
      self.modalIsOpen(false);
      resetForm();
    };

    self.validar = function(data, event) {
      if (Natal.Validation.validate(form)) {
        console.log('validacion true');
      } else {
        console.log('validacion false');
      }
    };

    self.selectedItem = Natal.observable({
      codigo: Natal.observable(12345),
      descripcion: Natal.observable('Whatever'),
      comments: Natal.observable('')
    });
  };

  var myViewModel = new ViewModel();

  Natal.applyBindings(myViewModel).done(function() {
    Natal.Validation.init('#editForm');
  });

});
<script src="https://natalfwk.gruposancorseguros.com/1.4.6/natal.min.js"></script>
<link href="https://natalfwk.gruposancorseguros.com/1.4.6/natal.min.css" rel="stylesheet" />
<div id="myToolbar">
  <button class="btn btn-primary" data-toggle="modal" data-bind="click:openModal">New</button>
</div>
<div id="modalNuevo" data-bind="modal:modalIsOpen" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-scrollable">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span>

        </button>
        <h4 class="modal-title">Generic Title</h4>

      </div>
      <div class="modal-body">
        <form id="editForm" class="">
          <div class="form-body" data-bind="with: selectedItem">
            <div class="row">
              <div class="form-group col-md-3">
                <label for="inCodigo" class="control-label">Code</label>
                <input type="text" class="form-control" id="inCodigo" name="inCodigo" data-bv-notempty="true" data-inputmask="'alias': 'integer'" data-bind="value: codigo" />
              </div>
            </div>
            <div class="row">
              <div class="form-group col-md-6">
                <label for="inDescripcion" class="control-label">Description</label>
                <input type="text" class="form-control" id="inDescripcion" name="inDescripcion" data-bv-notempty="true" data-bind="value: descripcion" />
              </div>
            </div>
            <div class="row">
              <div class="form-group col-md-6">
                <label for="description" class="control-label">Comments</label>
                <textarea class="form-control" cols="20" id="textArea" rows="3"></textarea>
              </div>
            </div>
          </div>
        </form>
      </div>
      <div class="modal-footer">
        <button nf-btn-guardar-registro type="button" class="btn btn-primary" data-bind="click:validar">Save</button>
        <button nf-btn-cancelar-modal type="button" class="btn btn-link" data-bind="click: closeModal">Cancel</button>
      </div>
    </div>
  </div>
</div>