0

From a high level: I have inherited some complex form manipulation code that has a major usability bug--editing a text field moves the cursor to the end of the entered text after each change.

I looked at this question which seems close, but not quite answering my question because the elements in question are using the include-replace pattern.

I'm having a hard time figuring out how to combine these approaches. I don't want to change the entered text, just make sure the cursor doesn't hop around.

As I understand it, the link function gets called when the partial is recompiled, which is happening whenever a change to the underlying model occurs, which happens every time the user edits the field at all. I can capture the cursor location by adding an event handler to the link function of my include-replace, but this doesn't have access to the element that is going to be swapped in.

myModule.directive('includeReplace', function () {
return {
    require: 'ngInclude',
    restrict: 'A', /* optional */
    link: function (scope, el, attrs) {
        el.replaceWith(el.children());

        el.on('change', function(event){
         var cursorPosition = event.target.selectionEnd;
         console.log(cursorPosition); // where I expect it
         el.selectionEnd; = cursorPosition; // but obviously this don't work
        });
        }

    }; 
});

I definitely don't have a super-strong grasp of the whole angular compile/link lifecycle, though I have read all the docs more than once. A comprehensive flow-chart would be nice...

Community
  • 1
  • 1
Ben
  • 4,980
  • 3
  • 43
  • 84

2 Answers2

0

Instead doing:

el.on('change', function(event){
         var cursorPosition = event.target.selectionEnd;
         console.log(cursorPosition); // where I expect it
         el.selectionEnd; = cursorPosition; // but obviously this don't work
        });
        }

What about doing:

scope.$watch(function () {
  return el.val();
}, function (value) {
  $timeout(function(){
    var cursorPosition = event.target.selectionEnd;
    console.log(cursorPosition); // where I expect it
    el.selectionEnd = cursorPosition;
  });
});

Don't forget to include $timeout in your directive.

Hope this helps!

Mindastic
  • 4,023
  • 3
  • 19
  • 20
  • With scope.$watch you are "watching" the element value and it will fire the function below each time it changes. – Mindastic Jul 09 '15 at 19:03
  • I think this results in a similar issue to the other way, in that the element doesn't really "change", it is wholly replaced. Basically, that watch function never fires after the very first time it is created, because every time the model changes, the whole element is replaced. – Ben Jul 09 '15 at 19:20
  • OK, i see. In that case, i didn't understand the question, sorry about that. Anyway, what happens if you watch the model instead the value? Doesn't it work either? – Mindastic Jul 09 '15 at 19:23
  • I don't think the model knows anything about the cursor location – Ben Jul 09 '15 at 19:28
0

Well, for my purposes, it turns out I simply needed to add the ng-model-options="{ updateOn: 'blur' }" to the html. This prevents the model from updating and triggering the replace until the user is finished editing.

Ben
  • 4,980
  • 3
  • 43
  • 84