1
votes

I'm currently trying to create a custom binding for my webpage, where I have a visible span and hidden input element. If I'm to click on the span, it will disappear and the input will appear. Once the input loses focus, the span is updated with the new value from the input. However, for some reason my blur function is being binded again each time I click my span, which is not what I want. How can I fix this?

HTML

<!-- ko foreach: formula -->
  <span data-bind="text: $data, attr: {name: $index}, convert: $index()"></span>
  <input data-bind="value: $data, attr: {name: $index}" class="hide"/><br/>
<!-- /ko -->

JavaScript

ko.bindingHandlers.convert = {
  init: function(element, valueAccessor) {
    $(element).click(function() {
      var index = valueAccessor();
      var inputName = "input[name="+index+"]";
      $(element).addClass("hide");
      $(inputName).removeClass("hide").focus().blur(function() {
        console.log("firing");
        $(inputName).addClass("hide");
        $(element).removeClass("hide");
        $(element).text($(inputName).val());
      });
    });
  }
};

So if I click on my span twice, I would get

firing
firing
firing

in my console when I'm only supposed to get firing twice.

Note: I can't follow the hasFocus example from the Knockout tutorial as it binds to all input fields, and I need my input fields to toggle only for that specific span that is being clicked.

1

1 Answers

3
votes

This is not a mystery at all. Look at that code:

$(element).click(function() {
    /* some code */
    $(inputName).blur(function() {
        /* some code */
    });
});

Each time you click you add blur handler. You may try removing handlers like this:

$(element).click(function() {
    var $element = $(this);
    var index = valueAccessor();
    var inputName = "input[name="+index+"]";
    var $input = $(inputName);
    $element.addClass("hide");
    $input.unbind('blur');
    $inputName.removeClass("hide").focus().blur(function() {
        console.log("firing");
        $input.addClass("hide");
        $element.removeClass("hide");
        $element.text($input.val());
    });
});

I think you can chain it, didn't test it though.