I have an observable name field in my knockout view model. Now i want to limit the number of characters in this field if it exceeds certain number.
As if name = "john smith" and i have a limit of 6 characters then
display " john s... "
Another reusable solution is to create a custom binding that displays a trimmed version of the text.
This allows the underlying value to remain unaffected, but trims the text for display purposes. This would be useful for something like a message preview, or for fitting data into a grid column.
Example binding:
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
};
}
};
Use it like this:
<div data-bind="trimText: myText1"></div>
or...
<div data-bind="trimText: myText1, trimTextLength: 10"></div>
See Fiddle
<span data-bind="text: (name.length > 6 ? name().substring(0, 5) + '...' : name)"></span>
Or you can create a computed observable in your ViewModel, such as:
var self = this;
this.shortName = ko.computed(function() {
return (self.name.length > 6 ? self.name().substring(0, 5) + '...' : self.name);
});
and then:
<span data-bind="text: shortName"></span>
Chris Dixon's solutions are perfect if you have one field that has a max length. But if you have to repeat this operation multiple times it becomes cumbersome. That is when you should write a custom observable extender, like this:
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;
};
You can then use it on any observable, and you can specify a different maximum length for any of them. This removes the clutter from the HTML (solution 1), and the necessity to write a computed observable (solution 2). You simply define your observable the following way:
this.shortName = ko.observable().extend({ maxLength: 25 });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With