Reputation: 287
I'm not sure exactly what the issue is, but something weird is going on. I have a contenteditable directive that lets me assign an ng-model to a div (which I got from the some angular documentation), which I'm using to save the changes made in the div.
In my html, I have: (I'm linking the textarea to the div so I can confirm the binding is working)
<button ng-click="addPage()">Add Page</button>
<div ng-repeat-start="item in book" ng-model="item.v" contenteditable></div>
<textarea ng-model="item.v" ng-repeat-end></textarea>
The problem is that the ng-repeat produces an empty div/textarea even though I specified a base model in my controller:
$scope.book = [{v: "asd", t: "test"}];
$scope.addPage = function(){
$scope.book.push({v: "", t: "test"});
};
Shouldn't the div be loaded with the value "asd"? The curious thing is when I use the console log to see $scope.book
, It has the correct value for the t
property, but not thev
property. When I change the html code from item.v
to item.t
, then the reverse happens in the console log, and it's the "t" property that gets overwritten.
It's almost as if $scope.book
is being overwritten by the ng-repeat. After the page has loaded, I can add as many of these divs as I want, type in them, and then when I check the console log, there are being saved to $scope.book correctly. But something seems to be happening initially.. Any help?
Solution As pointed out in the comments, the problem was with the content editable directive, which you can see in action over here. Specifically, I don't know why exactly and I'd love to find out, but the error occurs here:
read(); // initialize
// Write data to the model
function read() {
var html = element.html();
// When we clear the content editable the browser leaves a <br> behind
// If strip-br attribute is provided then we strip this out
if ( attrs.stripBr && html == '<br>' ) {
html = '';
}
ngModel.$setViewValue(html);
}
$setViewValue
is overwriting the ngModel somehow, so all I had to do (as suggested by New Dev) was comment out the read()
function and it works great now.
Upvotes: 1
Views: 454
Reputation: 49580
Input directives - both built-in and custom - require: "ngModel"
. That is to say that they use the ngModel
pipeline to marshal data between the Model and the View through a pipe of $formatters
, $parsers
and $validators
.
An input control (doesn't have to be <input>
) would call $setViewValue
when it detects that its "View" state has changed (typically a DOM interaction has happened, but could be for whatever reason - could be based on $interval
).
An input control would also define ngModel.$render
to render its DOM in response to a change coming from the Modal side.
And typically, the Model takes precedence over the View, because ultimately, the View should be driven by the Model (i.e. ViewModel).
This doesn't happen with your contenteditable
. In fact, it calls read()
to "initialize" based on its View data. Since it is empty, it sets (via `$setViewValue - something one would do when a user has interacted with the control) the ngModel-bound value to be empty.
Removing the call to read()
fixes the issue.
Upvotes: 2