1

I have a textarea which allows users to put in 16 lines. I've build an directive for that purpose, and everything works fine, if the user hits enter.

But I also want to prevent more than 16 lines, even if the user does not hit enter, but puts in a very long text, which is displayed into multiple lines (forced line break).

The background of this question is the following: I have a postcard, and users should be able to enter text to this postcard. The postcard has a fixed width/height. The textarea should represent the fixed width/height of the postcard, so users can see how many space they have left to fill out the postcard (not more than 16 lines).

Is this possible with JS?

My code so far:

HTML

<textarea placeholder="Enter text" rows="16" ng-trim="false" id="message-textarea" maxlines="16" maxlines-prevent-enter="true"></textarea>

JS Directive

app.directive('maxlines', function() {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, elem, attrs, ngModel) {
      var maxLines = 1;
      attrs.$observe('maxlines', function(val) {
        maxLines = parseInt(val);
      });
      ngModel.$validators.maxlines = function(modelValue, viewValue) {
        var numLines = (modelValue || '').split("\n").length;
        var diffLines = maxLines - numLines;
        scope.$emit('cliked-from-directive-maxlines', {diffLines});
        return numLines <= maxLines;
      };
      attrs.$observe('maxlinesPreventEnter', function(preventEnter) {
        // if attribute value starts with 'f', treat as false. Everything else is true
        preventEnter = (preventEnter || '').toLocaleLowerCase().indexOf('f') !== 0;
        if (preventEnter) {
          addKeypress();
        } else {
          removeKeypress();
        }
      });

      function addKeypress() {
        elem.on('keypress', function(event) {
          // test if adding a newline would cause the validator to fail
          if (event.keyCode == 13 && !ngModel.$validators.maxlines(ngModel.$modelValue + '\n', ngModel.$viewValue + '\n')) {
            event.preventDefault();
          }
        });
      }

      function removeKeypress() {
        elem.off('.maxlines');
      }

      scope.$on('$destroy', removeKeypress);
    }
  };
});
John Brunner
  • 2,842
  • 11
  • 44
  • 85
  • Find a jquery solution here: http://stackoverflow.com/questions/6501043/limit-number-of-lines-in-textarea-and-display-line-count-using-jquery – danii Jun 27 '16 at 09:07

3 Answers3

0

AFAIk there is no way to read or restrict the number of lines of a textarea. Your best chance IMHO is using 16 single-line inputs and focus the next row whenever the user hits the chars-per-line limit.

Hubert Grzeskowiak
  • 15,137
  • 5
  • 57
  • 74
0

Try this

function addKeypress() {
   var lines = 16;
   elem.on('keypress', function(e) {
        var newLines = elem.val().split("\n").length;
        if(e.keyCode == 13 && newLines >= lines) {
            return false;
        }
    });
  });
}
Pajar Fathurrahman
  • 991
  • 1
  • 9
  • 19
0

Maybe you can do something like this:

JavaScript

$(".limit").on("input", function(evt) {
  var $limit = $(this);
  var limit = this;
  if($limit.innerHeight() !== limit.scrollHeight) {
    $limit.val($limit.data("before"));
    evt.preventDefault();
    return false;
  } else {
    $limit.data("before", $limit.val());
  }
}).each(function(index, el) {
  $(el).data("before", $(el).val());
});

HTML

<textarea class="limit" rows="10"></textarea>

CSS

.limit {
  max-width: 300px;
  min-width: 300px;
  resize: none;
  overflow: hidden;
}
Arg0n
  • 8,283
  • 2
  • 21
  • 38
  • Thanks, this works great. Question: when I enter some text to the limits (till the last line and last char), and after re-entering the textarea-view, everything gets deleted when I enter a letter to the last line (it happens just to the last line). Do you know why? – John Brunner Jun 27 '16 at 14:39
  • By re-entering I mean going back and forth in browser history. – John Brunner Jun 27 '16 at 14:45
  • @JohnBrunner Yeah, it's because the `$limit.data("before");` is not set. You can set it when the page loads to initialize it to a value. (To `$limit.data("before", $limit.val());`). See updated answer. – Arg0n Jun 28 '16 at 09:52