It turns out I was following a pretty nasty anti-pattern when it comes to AngularJS. I was binding attributes to functions in my HTML. Most often, this was in the form of ng-disabled="isThisFieldDisabled()"
.
The problem was I was calculating whether the field should be disabled every time the function was called. In cases where the data was loaded asynchronously, these functions would first need to check if the data had been loaded yet.
function ($scope, someFactory) {
someFactory.then(function (data) {
$scope.data = data;
});
$scope.isThisFieldDisable = function () {
if (!angular.isDefined($scope.data)|| $scope.data === null) {
return true;
}
return $scope.data.someCondition;
};
}
A much easier approach is to simply update the condition when the data is returned from the call:
function ($scope, someFactory) {
$scope.someCondition = true;
someFactory.then(function (data) {
$scope.someCondition = data.someCondition;
});
$scope.isThisFieldDisable = function () {
return $scope.someCondition;
};
}
Of course, once you are just returning the $scope
value, the function becomes unnecessary. You can update the HTML like so ng-disabled="someCondition"
and the controller ends up much more straight-forward:
function ($scope, someFactory) {
$scope.someCondition = true;
someFactory.then(function (data) {
$scope.someCondition = data.someCondition;
});
}
In most cases, I actually converted my $scope
functions into local functions. They contained the logic for "calculating" the value of the backing field, so it made sense to call them from the $http
callbacks. I usually had to add parameters since I wasn't dumping as much in the $scope
anymore.