In my current project using angularJS, I have encountered a challenge while working with an API service to fetch and display data in different parts of the app under various controllers.
Initially, everything ran smoothly until I centralized the API calls in a factory to avoid redundant requests and efficiently manage the shared data. However, this approach brought about a new issue where the changes made after data retrieval were not immediately reflected in the view without manual interaction.
To address this issue, I experimented with $scope.$apply and $scope.$watch methods, which helped me achieve the desired functionality, but it led to incorporating delays in multiple sections, which felt unnatural in terms of coding practices.
Let's take a look at an example involving the user profile code snippet:
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>Demo</title>
</head>
<body ng-app="app" ng-controller="DashboardCtrl">
<div ng-init="getOwnProfile()">
<h1>My account</h1>
<form class="inline-form" role="form">
<input type="hidden" value="2" name="id"/>
<div class="form-group has-error">
<ul class="input-grp-2">
<li><input name="first_name" type="text" ng-model="profile.first_name" placeholder="First name" /></li>
<li><input name="last_name" type="text" ng-model="profile.last_name" placeholder="Last name" /></li>
</ul>
</div>
<input name="phone" type="text" ng-model="profile.phone" placeholder="Phone number"/>
<textarea name="information" rows="7">{{ profile.information }}</textarea>
<a href="#" class="button btn-add-photo"><span class="glyphicon glyphicon-camera"></span> Add Photo</a>
<input style="display: none" type="file" name="image" class="upload-photo" id="input_upload" accept="image/*"/>
</form>
<a href="" target="_self" class="button btn-green" ng-click="updateProfile(profile)">Submit Changes</a>
</div>
<script src="/js/app.js"></script>
<script src="/js/controllers/dashboard.js"></script>
<script src="/js/api.js"></script>
</body>
</html>
The dashboard controller implementation:
$scope.profile = null;
$scope.getOwnProfile = function () {
$scope.$watch( 'profile', function() {
setTimeout(function () {
$scope.$apply(function () {
$scope.profile = API.getOwnProfile();
});
}, 100);
})
};
The API service method handling the user profile:
var APIService = {};
var ownProfile;
APIService.resetRenterProfile = function() {
ownProfile = undefined;
};
APIService.getOwnProfile = function() {
if (typeof ownProfile === 'undefined') {
retrieveOwnProfile();
}
return ownProfile;
};
retrieveOwnProfile = function() {
return Restangular.one('profile', null).get() // GET: /profiles
.then(function (profile) {
ownProfile = profile;
});
};
return APIService;
While this solution works, there are two major drawbacks:
1) The updated data does not reflect in the view until the user interacts with certain elements like dropdown menus or tabs.
2) The necessity of specifying a delay in milliseconds introduces a potential UI inconsistency if the backend API call exceeds that time limit.
Although functional, I believe there might be a more efficient way to handle these issues. Any suggestions or guidance on improving this approach would be greatly appreciated.
Thank you for your input.