Нокаут: ограничение числа символов в наблюдаемом поле

У меня есть наблюдаемое поле имени в моей модели с нокаутом. Теперь я хочу ограничить количество символов в этом поле, если оно превышает определенное число.

Как будто name = "john smith", и у меня есть предел в 6 символов, а затем  дисплей "john s..."

Ответ 1

Другим многоразовым решением является создание настраиваемой привязки, которая отображает обрезанную версию текста.

Это позволяет базовому значению оставаться незатронутым, но обрезает текст для отображения. Это было бы полезно для чего-то вроде предварительного просмотра сообщения или для подбора данных в столбце сетки.

Пример привязки:

ko.bindingHandlers.trimLengthText = {};
ko.bindingHandlers.trimText = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
        var trimmedText = ko.computed(function () {
            var untrimmedText = ko.utils.unwrapObservable(valueAccessor());
            var defaultMaxLength = 20;
            var minLength = 5;
            var maxLength = ko.utils.unwrapObservable(allBindingsAccessor().trimTextLength) || defaultMaxLength;
            if (maxLength < minLength) maxLength = minLength;
            var text = untrimmedText.length > maxLength ? untrimmedText.substring(0, maxLength - 1) + '...' : untrimmedText;
            return text;
        });
        ko.applyBindingsToNode(element, {
            text: trimmedText
        }, viewModel);

        return {
            controlsDescendantBindings: true
        };
    }
};

Используйте его следующим образом:

<div data-bind="trimText: myText1"></div>

или...

<div data-bind="trimText: myText1, trimTextLength: 10"></div>

Смотрите Fiddle

Ответ 2

<span data-bind="text: (name.length > 6 ? name().substring(0, 5) + '...' : name)"></span>

Или вы можете создать вычисленное наблюдаемое в вашей ViewModel, например:

var self = this;

this.shortName = ko.computed(function() {
   return (self.name.length > 6 ? self.name().substring(0, 5) + '...' : self.name);
});

а затем:

<span data-bind="text: shortName"></span>

Ответ 3

Решения Chris Dixon идеальны, если у вас есть одно поле с максимальной длиной. Но если вам придется повторять эту операцию несколько раз, она становится громоздкой. Это когда вы должны написать пользовательский наблюдаемый расширитель, например:

ko.extenders.maxLength = function(target, maxLength) {
    //create a writeable computed observable to intercept writes to our observable
    var result = ko.computed({
        read: target,  //always return the original observables value
        write: function(newValue) {
            var current = target(),
                valueToWrite = newValue ? newValue.substring(0, Math.min(newValue.length, maxLength)) : null;

            //only write if it changed
            if (valueToWrite !== current) {
                target(valueToWrite);
            } else {
                //if the rounded value is the same, but a different value was written, force a notification for the current field
                if (newValue !== current) {
                    target.notifySubscribers(valueToWrite);
                }
            }
        }
    });

    //initialize with current value to make sure it is rounded appropriately
    result(target());

    //return the new computed observable
    return result;
};

Затем вы можете использовать его на любом наблюдаемом, и вы можете указать другую максимальную длину для любого из них. Это устраняет беспорядок из HTML (решение 1) и необходимость записи вычисленного наблюдаемого (решение 2). Вы просто определяете свой наблюдаемый следующим образом:

this.shortName = ko.observable().extend({ maxLength: 25 });

Ответ 4

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

ko.extenders.truncateValue = function(target, option) {                            
        target.subscribe(function (newValue) {
            if(newValue.length > option){
                target(newValue.substring(0,option));
            }                    
        });

        return target;
    };

Затем создайте настраиваемую привязку, которая добавит расширитель к наблюдаемому:

ko.bindingHandlers.maxLength = {
    init:  function (element, valueAccessor, allBindingsAccessor, viewModel) {
        'use strict';                     

        var maxlength = element.getAttribute("maxlength");

        valueAccessor().extend({truncateValue: maxlength })
        ko.bindingHandlers.value.init(element, valueAccessor, allBindingsAccessor, viewModel);    
    }   
};

В html вы применяете привязку maxLength следующим образом:

<input type="number" data-bind="maxLength: yourObservable" maxlength="9"></input>