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

Автоматически обрезать пробелы по всем наблюдаемым значениям

У меня есть ViewModel в нокауте, который получен в основном из плагина сопоставления (то есть динамически). Это прекрасно работает. Тем не менее, теперь мой клиент хочет, чтобы я убедился, что все входы имеют пробелы, отделенные от перед отправкой на сервер. Очевидно, что код обрезки очень прост, но, будучи относительно новым для Knockout, я точно не знаю, где разместить этот код. Я читал о extenders, но это кажется довольно многословным и повторяющимся, чтобы вернуться назад и добавить это к каждому наблюдаемому. Плюс я даже не уверен, что могу сделать это для динамически генерируемых наблюдаемых (a la, плагин отображения).

Есть ли какой-либо центральный механизм, который я могу расширить/переопределить, где я могу вставлять некоторый код обрезки каждый раз, когда наблюдаемые изменения? В основном я стараюсь избегать часов, потраченных на все наши формы и добавляя специальный синтаксис привязки в HTML, если мне это не нужно.

Спасибо.

4b9b3361

Ответ 1

У меня была та же проблема. Я написал расширение, поэтому вы можете вызвать trimmed в своей модели просмотра, не изменяя привязки. Например:

var vm = {
    myValue: ko.observable('').trimmed()
}

Расширение:

ko.subscribable.fn.trimmed = function() {
    return ko.computed({
        read: function() {
            return this().trim();
        },
        write: function(value) {
            this(value.trim());
            this.valueHasMutated();
        },
        owner: this
    });
};

Код на JSFiddle с примерами.

Ответ 2

На всякий случай, если кто-то столкнется с этой проблемой с более новыми версиями Knockout, текущий топ-ранжированный ответ будет работать неправильно.

Здесь обновлен fiddle и код, чтобы отобразить необходимые изменения:

ko.subscribable.fn.trimmed = function() {
    return ko.computed({
       read: function() {
           return this().trim();
       },
       write: function(value) {
           this(value.trim());
           this.valueHasMutated();
       },
       owner: this
   }).extend({ notify: 'always' });
};

Если кто-нибудь знает, зачем нужен extend, пожалуйста, дайте мне знать. Мне потребовалось бесконечно, чтобы понять, почему он не работает правильно в Knockout 3.1.0

Ответ 3

Вы можете написать пользовательскую привязку, которая обрезает наблюдаемую. Что-то похожее на это

http://jsfiddle.net/belthasar/fRjdq/

Ответ 4

Используя решение Joe в качестве отправной точки, мы внедрили его несколько иначе.

Примечание:

  • В круглых скобках ko.observable() нет ничего
  • Новая функция чтения trimmed просто возвращает this() и не получает никаких исключений типа null или undefined.

Код модели:

var vm = {
    myValue: ko.observable().trimmed()
}

Расширение:

ko.subscribable.fn.trimmed = function() {
    return ko.computed({
        read: function() {
            return this();
        },
        write: function(value) {
            this(value.trim());
            this.valueHasMutated();
        },
        owner: this
    });
};

Ответ 5

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

Основная идея:

  • Перехватить привязку value
  • Оберните пройденный наблюдаемый в computed
  • Сделайте привязку read и write от вычисленного вместо исходного наблюдаемого
  • Когда приходит новый вход, обрезайте его, прежде чем мы его напишем
  • Когда изменяется значение модели, обрезайте его и обновите как модель, так и UI при необходимости

ko.bindingHandlers.trimmedValue = {
  init: function(element, valueAccessor, allBindings) {
    const ogValue = valueAccessor();
    let newVa = valueAccessor;
    
    // If this is a type="text" element and the data-bound value is observable,
    // we create a new value accessor that returns an in-between layer to do
    // our trimming
    if (element.type === "text" && ko.isObservable(ogValue)) {
      const trimmedValue = ko.observable().extend({"trim": true});
      
      // Write to the model whenever we change
      trimmedValue.subscribe(ogValue);
      
      // Update when the model changes
      ogValue.subscribe(trimmedValue);
      
      // Initialize with model value
      trimmedValue(ogValue());
      
      // From now on, work with the trimmedValue 
      newVa = () => trimmedValue;
    }

    // Note: you can also use `ko.applyBindingsToNode`
    return ko.bindingHandlers.value.init(element, newVa, allBindings)
  }
}

// Our observable to check our results with
var myObs = ko.observable("test ");
myObs.subscribe(function(newValue) {
  console.log("Change: \"" + newValue + "\"");
});

// The extender that does the actual trim
ko.extenders.trim = function(target, option) {
  return ko.computed({
    read: target,
    write: function(val) {
      target(
        val && typeof val.trim === "function"
          ? val.trim()
          : val
      );

      // This makes sure the trimming always resets the input UI
      if (val !== target.peek()) {
        target.valueHasMutated();
      }
    }
  }).extend({notify: "always"});
};

ko.applyBindings({
  myObs: myObs
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<h4><code>type="text" trimmedValue</code></h4>
<input type="text" data-bind="trimmedValue: myObs">

Ответ 6

Альтернативный подход, который хорошо работает для нас - обрезать, когда поле редактируется:

$(document.body).on('blur', 'input, textarea', function () { this.value = this.value.trim(); $(this).trigger('change'); });

Триггер события 'change' гарантирует, что KO обнаружит изменение (протестировано с KO v2).