Search code examples
angularjscontenteditableangular-ngmodel

Using contenteditable with ng-model inside ng-repeat?


Here is my issue: I am using ng-repeat to make a list of spans. Each span has the contenteditable attribute and ng-model directive. Everything works as expected (including two-way data binding), until I try to add a new item to the list.

<div ng-repeat="item in list">
    <span ng-model="item.text" contenteditable></span>
</div>
<button ng-click="addItemToList"></button>

The methods look like this:

$scope.addItemToList = function () {
    $scope.list.push({text: 'dummy text'});
}

or

$scope.addItemToList = function () {
    $scope.list.splice(1, 0, {text: 'dummy text'});
}

When adding the new item to the list (push or splice), the DOM updates, but the last item is initialised empty, with no text whatsoever. The last item in the model list also empties out, even if I specifically push an element with text in it.

After a few tests, I've noticed that this only happens if the list's length is bigger after modifying it: if I try to replace/modify/remove (not add) an element in the list, it works well. I believe this has to do with the way contenteditable elements initialise in the DOM (I think they initialise empty, and somehow, the model empties out as well).

Has anyone encountered this problem before? If yes, how did you solve it / what workaround have you found?


Solution

  • Based on the angular docs related to ngModelController, it seems that there is not built-in support for two-way data binding with contenteditable elements, seeing as in the plunkr example they wrote their own contenteditable directive. You might be able to use a modified version of that as a workaround.

    It looks to be a similar problem as this question and the contenteditable directive there looks similar to the contenteditable directive in the angular docs example.

    I also found this directive on github that might accomplish what you are trying to do.


    Edit: I did a new version of the plunk I posted in the comment above: https://plnkr.co/edit/v3elswolP9AgWHDIPwCk

    In this version I added a contenteditable directive that appears to be working correctly. It is basically a spin off of how the input[type=text] directive is written in angular, but I took out the places where it handles different types of input (since in this case it will just be text) and the places where it handles events that contenteditable elements don't even fire. I also changed it so that the $viewValue gets updated based on element.html() instead of element.val(). You might be able to use something like this as a workaround