Do not allow typing in textarea if it has too many characters

空扰寡人 提交于 2020-01-15 19:16:27

问题


I am trying to do the following functionality. Show a number of characters left in the textarea and disallow entering anything else if you already exceeded the maximum number.

I am confused with how to achieve this. Now I have something like this:

<textarea data-bind="textInput: message"></textarea>
<p>Characters left : <span data-bind="text: charLeft"></span></p>

function Vm_app() {
    var self = this;
    this.message = ko.observable('');
    this.charLeft = ko.pureComputed(function(){
        return 128 - self.message().length;
    });
}
ko.applyBindings(new Vm_app());

Any idea how should I proceed?

P.S. I know how to achieve the task with listening for events, but I do not want to break MVVM paradigm.

P.S.2 the linked answer does not allow to continue adding the text, once you disabled it. I want only to disallow writing new characters (a person will be able to click delete, backspace).


回答1:


As I stated earlier, you'd be better off not trying to restrict typing beyond a certain length. There are many things to consider when you want to intercept these sorts of things, many corner cases you would have to work around to have it work naturally. And more importantly, it would be a much better experience for the user to be able to type out all that they want to type with no restrictions, at least until they try to submit. Then that's when you can enforce that it needs to be a certain length.

With that said, there are some things you can do to make this work close enough. There are many approaches you can take to enforce this. Probably the simplest approach would be to create a delegating observable which can intercept writes to your observable. You could then check the length if appropriate and set the value, or ignore it. You could keep this all self-contained in an extender.

ko.extenders.maxlength = function (target, maxlength) {
    var view = ko.dependentObservable({
        read: target,
        write: function (value) {
            if (value.length <= maxlength) {
                target(value);
            } else {
                view.notifySubscribers(target()); // "refresh" the view
            }
        }
    });
    target.view = view;
    target.maxlength = maxlength;
    return target;
};

Then to use it:

this.message = ko.observable('').extend({ maxlength: 128 });

Then just bind to the view:

<textarea data-bind="textInput: message.view"></textarea>

Just note that when "refreshing", the cursor will always be moved to the end. Just the nature of setting the values. If you want to preserve the cursor position, you'll have to reset that as well.

fiddle




回答2:


I solved it with a reusable ViewModel

define(["knockout"], function(ko) {
    var ctor = function(limit, limitWarning) {
        this.text = ko.observable("");
        this.isEditing = ko.observable();

        this.limitedText = ko.computed({
            write: this.setText,
            read: this.text
        }, this);

        this.limit = limit;
        this.limitWarning = limitWarning;
        this.charactersLeft = ko.computed(this.getCharactersLeft, this);
        this.charactersLeftWarning = ko.computed(this.getCharactersLeftWarning, this);
        this.limitReached = ko.computed(this.getLimitReached, this);
    };


    ctor.prototype = {
        setText: function(text) {
            if (text.length > this.limit) {
                text = text.substring(0, this.limit);
            }

            this.text(text);
        },
        getCharactersLeft: function() {
            return this.limit - this.text().length;
        },
        getCharactersLeftWarning: function() {
            return this.getCharactersLeft() <= (this.limit * this.limitWarning);
        },
        getLimitReached: function() {
            return this.text().length >= this.limit;
        },
        writing: function(model, e) {
            return e.keyCode < 65 || !this.getLimitReached();
        }
    };

    return ctor;
});

View

<textarea data-bind="text: limitedText,valueUpdate: 'afterkeydown', event: { keydown: writing }" class="form-control" rows="5"></textarea>
<div data-bind="css: { 'limit-warning': charactersLeftWarning, 'limit-reached': limitReached }">
    Characters left <span data-bind="text: charactersLeft"></span>
</div>



来源:https://stackoverflow.com/questions/26500978/do-not-allow-typing-in-textarea-if-it-has-too-many-characters

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!