Подтвердить что ты не робот

Нокаут contentEditable binding

Я написал специальный обработчик привязки, который переключает, является ли элемент contentEditable. Я также хочу, чтобы любые привязки html обновлялись при редактировании содержимого элемента, поэтому он прослушивает входные события и обновляет привязки html, если они доступны.

ko.bindingHandlers.contentEditable = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.unwrap(valueAccessor());
        element.contentEditable = value;

        var $element = $(element);

        if (value) {
            var allBindings = allBindingsAccessor();
            var htmlBinding = allBindings.html;

            if (ko.isWriteableObservable(htmlBinding)) {
                $element.on("input", function (event) {
                    htmlBinding(element.innerHTML);
                });
            }
        } else {
            $element.off("input");
        }
    }
};

Однако, вот проблема:

  • Пользователь вводит что-то в элемент
  • Событие ввода запускает
  • Связывание html обновляется
  • Обновлен элемент innerHTML
  • Позиция курсора в элементе возвращается к началу

A jsfiddle говорит тысячу слов... http://jsfiddle.net/93eEr/1/

Я немного озадачен тем, как именно с этим справиться.

4b9b3361

Ответ 1

ko.bindingHandlers.htmlLazy = {
    update: function (element, valueAccessor) {
        var value = ko.unwrap(valueAccessor());
        
        if (!element.isContentEditable) {
            element.innerHTML = value;
        }
    }
};
ko.bindingHandlers.contentEditable = {
    init: function (element, valueAccessor, allBindingsAccessor) {
        var value = ko.unwrap(valueAccessor()),
            htmlLazy = allBindingsAccessor().htmlLazy;
        
        $(element).on("input", function () {
            if (this.isContentEditable && ko.isWriteableObservable(htmlLazy)) {
                htmlLazy(this.innerHTML);
            }
        });
    },
    update: function (element, valueAccessor) {
        var value = ko.unwrap(valueAccessor());
        
        element.contentEditable = value;
        
        if (!element.isContentEditable) {
            $(element).trigger("input");
        }
    }
};

var viewModel = {
    editable: ko.observable(false),
    content: ko.observable("<i>This</i> is the initial content!")
};

ko.applyBindings(viewModel);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<label>Editable: <input type="checkbox" data-bind="checked: editable"/></label>
<hr>
<div data-bind="contentEditable: editable, htmlLazy: content"></div>
<hr>
<pre data-bind="text: content"></pre>

Ответ 2

@Ответ на ТОМАЛАК совершенен, следовательно, мой верхний.

Но для тех, кто прибывает сюда, как и я:

  • поиск одноразовых пользовательских привязок
  • который предполагает, что содержимое всегда доступно для редактирования
  • в порядке с value: -специальными обновлениями (то есть: по размытию)

Я предлагаю следующее:

ko.bindingHandlers.contentEditable = {
    init: function(element, valueAccessor) {
        var value = valueAccessor();

        function onBlur(){
            if (ko.isWriteableObservable(value)) {
                value(this.innerHTML);
            }
        };                

        element.innerHTML = value(); //set initial value
        element.contentEditable = true; //mark contentEditable true
        element.addEventListener('blur', onBlur); //add blur listener
    }
};

Ответ 3

В предыдущих у меня есть проблемы с bdo, которые решают этот код. также этот код можно использовать для другого contentEditable. поэтому я предлагаю следующее:

 ko.bindingHandlers.bdoValue =
 ko.bindingHandlers.contentEditable = {
      'init': function(element, valueAccessor) {
          var updateHandler = function() {
              var modelValue = valueAccessor(),
                  elementValue = element.innerHTML;
              modelValue(elementValue);
          };
          ko.utils.registerEventHandler(element, "keyup", updateHandler);
          ko.utils.registerEventHandler(element, "input", updateHandler);
      },
      'update': function(elem, valueAccessor) {
          var value = ko.utils.unwrap(valueAccessor())||"";
          var current = elem.innerHTML;
          if (value !== current) {
              elem.innerHTML = value;    
          }
      }
   };