It is common knowledge for any Angular user with even a bit of experience that directly modifying the DOM from a controller is bad practice. One reason is that it results in DOM manipulation code which is localized and cannot be reused. From this excellent Toptal Angular tutorial, there are two more reasons not to manipulate the DOM from the controller:
- it violates the purpose of the controller, and
- the transcluded child content has not been added to the DOM
The first reason is obvious, since the controller was intended to be simply that, namely an entity which brokers information exchange between the view and the model. However, I don't understand what is meant by the second point.
This question was actually driven by a real UI problem I am currently facing. A developer in my team (who shall remain nameless) actually added code to one of our controllers which directly manipulates the DOM. Here is a small screen capture of the area of interest:
Clicking the pencil would turn my name into an editable text box. However, on some browsers we see a momentary flickering, where all the above DOM elements seem to jump all over the place. It appears that something very kinky is happening, and I would like to understand what it is.
Here is a boiled down version of the HTML from the above form:
<input class="usrProfileTextBox" id="displayNameTextBox"
ng-show="editingDisplayName" type="text" ng-model="displayName"
ng-keyup="$event.keyCode == 13 ? changeDisplayName() : null"
ng-blur="changeDisplayName()" />
<div class="usrProfileRightCol">
<label class="usrProfileNameLabel" ng-hide="editingDisplayName">{{displayName}}
</label>
<span ng-hide="editingDisplayName" ng-click="showEditDisplayName()"
class=" pointer-click glyphicon glyphicon-pencil"></span>
</div>
And, for completeness, here is the controller function which fires when a user clicks the edit button for the username box:
$scope.showEditDisplayName=function(){
$scope.previousDisplayName = $scope.displayName;
$scope.editingDisplayName = true;
$timeout(function() {
document.getElementById("displayNameTextBox").value=$scope.displayName;
document.getElementById("displayNameTextBox").focus();
});
}
Can anyone shed light on what is actually happening under the hood when our controller directly manipulates the DOM?