How to build a textarea with character counter and max length?
Asked Answered
P

5

10

Please consider this jsfiddle. It contains something along these lines:

<textarea data-bind="value: comment, valueUpdate: 'afterkyedown'"></textarea>

<br/><br/>
<span data-bind="text: getCount, valueUpdate: ['afterkeydown','propertychange','input']"></span> characters???

And this JavaScript:

var viewModel = function(){
    var self = this;

    self.count = ko.observable(0);
    self.comment = ko.observable("");
    self.getCount = function(){
        var countNum = 10 - self.comment().length;
        self.count(countNum);
    };
}

var viewModel12 = new viewModel();
ko.applyBindings(viewModel);

I have a textarea where the maxlength should be 20 characters. When the number of characters reaches 20, it will be stop, and if you try to add more characters, they will be removed.

Note that this also has to work for copy/paste: if a user pastes more than 20 characters, only the first 20 will stay, and the rest of them should be removed.

Prinz answered 19/10, 2012 at 21:17 Comment(1)
B
8

Have a look at this jsfiddle, which works along these lines:

var viewModel = function(){
    var self = this;

    self.comment = ko.observable("");
    self.count = ko.computed(function(){
        var countNum = 10 - self.comment().length;
        return countNum
    });
}

var vm = new viewModel();
ko.applyBindings(vm);
<textarea data-bind="value: comment, valueUpdate: 'afterkeydown'"></textarea>
<br/><br/>
<span data-bind="text: count"></span> characters​​​​​​​

You need to learn about ko.computed() to do this sort of stuff...

Blueberry answered 19/10, 2012 at 21:27 Comment(1)
thank you. still need help to limit the text to only 20 characters. I still able to type more than 20 in the textarea.Prinz
M
7

Using a computed value only partially solves the problem. Disabling the textarea based on that computed value (as was done in Michael Berkompas's fiddle) doesn't really solve the problem. You need to use a custom binding to make this work. Using that fiddle as a starting point, we can use custom bindings to round it out:

http://jsfiddle.net/ReQrz/1/

Which is something like:

ko.bindingHandlers.limitCharacters = {
    update: function(element, valueAccessor, allBindingsAccessor, viewModel)
    {
       element.value = element.value.substr(0, valueAccessor());
       allBindingsAccessor().value(element.value.substr(0, valueAccessor()));
    }
};

And then doing:

<textarea data-bind="value: comment, valueUpdate: 'afterkeydown', limitCharacters: 20"></textarea>
Mend answered 27/11, 2012 at 8:39 Comment(3)
Awesome solution, however it doesn't work in KnockoutJS 3.0. Any idea why?Immigrate
@BrianDavidBerman, no clue. I stopped using Knockout in favor of Angular and haven't looked back.Mend
I had a look at it with KnockoutJS 3.0. Here's the fiddle for that one: jsfiddle.net/R3PxfMicroprint
D
1

This works for me in 3.0.0

    ko.bindingHandlers.maxLength = {
        update: function(element, valueAccessor, allBindings){
            if(allBindings().value()){
                allBindings()
                  .value(allBindings().value().substr(0, valueAccessor()));
            }
        }
    }
  <textarea data-bind="value: message, 
                       maxLength: 255, 
                       valueUpdate: 'afterkeydown'"></textarea>
Disgust answered 19/3, 2014 at 20:20 Comment(0)
D
0

Why not in the view do something like this:

<textarea data-bind="event: { keypress: enforceMaxlength }></textarea>

With this in the viewModel?

function enforceMaxlength(data, event) {
        if (event.target.value.length >= maxlength) {
            return false;
        }
        return true;
    }
Dikmen answered 26/2, 2014 at 21:43 Comment(0)
A
0

There is an attribute maxlength for textarea.

For your problem, I found a way without any function:

<textarea style="resize: none;" data-bind="value: payComments, valueUpdate: 'afterkeydown', attr: { maxlength: payCommentsMaxlength }"></textarea>
 var viewModel = function() {
  var self = this;

  self.payCommentsMaxlength = "20";
  self.payComments = ko.observable("");  
  
  self.payCommentsCountAndMax = ko.computed(function() {
    return self.payCommentsMaxlength - self.payComments().length;
  });
}

var vm = new viewModel();
ko.applyBindings(vm);

I have a similar task, you could look through it here: http://jsfiddle.net/KateKotova/h9cvj38L/12/

Arbitrate answered 1/4, 2021 at 10:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.