3

Using angular js here:

I have a HTML table and using contenteditable for each row data, eg as below:

<td contenteditable="true" 
    ng-repeat="column in targetTable.columns"
    ng-model="r[column.id]"
    ng-blur="!r.id? addNewRow(r[column.id], r): undefined">
</td>

I also have my directive as:

directive('contenteditable', ['$sce', function($sce) {
    return {
      link: function(scope, element, attrs, ngModel) {

        var regex =   /^[\w/\s_~`!@#$%^&*()_+-={}[\]|\:;/>\\\'\"]$/;      
        element.on('keypress', (e) => {
            char = String.fromCharCode(event.which);
            if (!regexpInt.test(char)) {
                event.preventDefault();
            };         
        });

        ngModel.$parsers.push(function (value) {
           if (value.length > 5) {
             value = value.substr(0, 5);
             ngModel.$setViewValue(value);
             ngModel.$render();
           }
           return value;
        });
      }
    }
});

I am just posting relevant code from the directive. The entire working code can be seen in the code pen below.

In the above directive I am using regex to allow user to type anything from the character set defined along with spl chars and space which works fine.

I am also using ngModel.$parsers trying to restrict the user entry to certain character limit (5 in this case), so if the user types more than 5, I want to the input to stop accepting more chars. The reason to apply limit here is this I would be creating dynamic columns and based on the column name I would be applying the maxlength of each so I cannot apply the limit on the in the html.

Now the issue comes with the maxlength code, it works not exactly as expected.

  • If you see the demo and start typing more than 5 characters, as soon as you type the 6th character the cursor comes to 1st character and keeps overwriting the existing if you type more chars.

  • Since I want to allow space in the input, if you type some char and add space it tries to add & n b s p; to the input.

What I want from the maxlength code is, it should accept spaces and as soon as you try to type more than 5th char it would prevent the user to typing and stop there itself. Similar to regex code.

Here is my below codepen demo: https://codepen.io/anon/pen/WKZJWw

Any inputs for fixing this issue?

georgeawg
  • 48,608
  • 13
  • 72
  • 95
kaka1234
  • 770
  • 3
  • 9
  • 30
  • Anyone for inputs? – kaka1234 Aug 01 '18 at 15:30
  • See if this helps https://stackoverflow.com/questions/512528/set-keyboard-caret-position-in-html-textbox – Pratyush Sharma Aug 02 '18 at 13:27
  • This code looks the same as code in [this question](https://stackoverflow.com/q/51485838/5535245) from [user1563677](https://stackoverflow.com/users/1563677/user1563677). What's going on here? Are you using two accounts for your questions? – georgeawg Aug 03 '18 at 09:23
  • Use inline edit pattern. I doubt you ever get this working normally. – Petr Averyanov Aug 03 '18 at 12:07
  • @georgeawg No I don't have 2 accounts. That is one of my teammate. We both are working on the same application but different module. And both have to deal with this contenteditable though different issue. We did not want to create a single post with 2 many questions. We are just maintaining the application so cant much change now and replace contenteditable. – kaka1234 Aug 03 '18 at 12:55
  • If you and your teammate are both creating `contenteditable` directives, then when the app includes both modules, the AngularJS framework will attach both contenteditable directives to every contenteditable element in the app. How are you planning to deal with conflicting behavior? – georgeawg Aug 04 '18 at 15:29

1 Answers1

2

To allow spaces, I would just remove it before setting the model value. So in the read function:

    html = html.replace(/&nbsp;/g, ' ')
    ngModel.$setViewValue(html);

To limit the characters, why not just stop inputs in your keypress function

   element.on('keypress', (e) => {
      char = String.fromCharCode(event.which)
      if (!regex.test(char)) {
        event.preventDefault();
      }

      if (ngModel.$viewValue && ngModel.$viewValue.length >= maxLength) {
            event.preventDefault();
      }
   });

where maxLength is 5. But you would still have to re-render in the case of pasting input or the user typing really fast. To get around this issue, set the position of the caret to the end of the input after each render.

  ngModel.$render = function() {
    element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
    var caretPosition = (ngModel.$viewValue && ngModel.$viewValue.length) || 0;
    setCaretPosition(caretPosition);
  };

Credit goes to this answer by Tim Down on how to set the caret position. In this case, it is defined as

    var setCaretPosition = function(position) {
        if (!element[0].childNodes[0]) {
              return;
        }
        var range = document.createRange();
        var selection = window.getSelection();
        range.setStart(element[0].childNodes[0], position);
        range.collapse(true);
        selection.removeAllRanges();
        selection.addRange(range);
    };

See updated codepen

logee
  • 5,017
  • 1
  • 26
  • 34
  • Could you also look at this post https://stackoverflow.com/questions/51485838/angularjs-required-field-validation-and-highlight-for-dynamic-rows-of-html-tabl for inputs please – kaka1234 Aug 03 '18 at 14:28