Text Counter & Limiter

by Jason Butz

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<textarea data-bind="textInput: v, charCount: 2048, charLimiter: 2048"></textarea>

SCSS

textarea {
    width: 100%;
    height: 32px;
}
span.text-counter {
    display: block;
    float: right;
    font-size: 0.8em;
}

JavaScript

function App() {
	var self = this;
    self.v = ko.observable('Hello World');
}

ko.bindingHandlers.charCount = {
	init: function(element, valueAccessor, allBindings, viewModel, bindingContext){
		// Get the character limit to display
        var charLimit = valueAccessor();
		// Get input value
        var inputText = allBindings().value || allBindings().textInput;
        // Create the computed to setup our text
		var counterText = ko.pureComputed(() => {
        	return inputText().length + ' / ' + charLimit;
        });
        // Create DOM elements
        var $counter = $('<span class="text-counter"></span>');
        // Add element after the element this is bound to
    	$(element).after($counter);
        // Apply binding to new element
        ko.applyBindingsToNode($counter.get(0), {
        	text: counterText
        });
    }
};

ko.bindingHandlers.charLimit = {
	init: function(element, valueAccessor, allBindings, viewModel, bindingContext){
		// Get the character limit to display
        var charLimit = valueAccessor();
		// Get input value
        var inputText = allBindings().value || allBindings().textInput;
        // Subscribe to text observable
        inputText.subscribe((newValue) => {
        	// If we have more than the allotted number of characters
        	if(newValue.length > charLimit) {
            	// hack off the extra
            	inputText(newValue.substr(0, charLimit));
            }
        })
    }
};

ko.applyBindings(new App());