The Problem
I'm trying to integrate the Adobe Creative SDK into my Angular app. The editor is initialized from a photo viewer modal by clicking a button, which triggers the function below. Once the editor has been initialized, the onReady
callback hides the photo viewer elements and the editor is appended to the modal. This part works great.
In my modal DOM I'm trying to use ng-show="editorOpen"
and ng-show="!editorOpen"
on the elements I wish to show or hide, depending on whether or not the editor is open. The first time I trigger $scope.editPhoto
, ng-show
works as expected. When I close the editor however, ng-show
fails to update the DOM. The editor disappears, however the hidden photo viewer elements remain hidden.
I'm no expert on Angular's digest cycle, but from what I've been able to find out from my research, I believe the problem is that the hidePreview()
and showPreview()
functions are being called during a digest cycle, causing ng-show
not to register the change to $scope.editorOpen
.
Once I close the editor and ng-show
fails to update the DOM, I can still trigger it manually by doing another action within the app that triggers a digest cycle, such as using the left/right arrow keys to try and navigate to the next photo in the viewer modal.
It gets weirder from here though. Once I've closed the editor and manually triggered a digest, everything seems normal. If I re-open the editor a second time, ng-show
stops working altogether, even if I try to manually trigger a digest using the method I just described.
Solutions I've Tried
I've tried a number of possible fixes, including every solution offered in this discussion to solve the problem, all of which have failed.
- I tried wrapping
$scope.editorOpen = true
and$scope.editorOpen = false
in a$timeout
function, since that should trigger a digest. I tried setting the delay to 0ms and 10ms. Both failed. - I created a scoped function
$scope.toggleEditor
to toggle$scope.editorOpen
and passed that into the Adobe Creative SDK image editor'sonSave
,onReady
, andonClose
callbacks, instead of theshowPreview()
andhidePreview()
functions I have in my code below. That also failed. - I tried wrapping my entire
$scope.editPhoto
function in a$timeout
function. Also failed. - I tried the more direct approach of manually calling
$scope.$apply()
as well as$scope.$digest()
within myshowPreview()
andhidePreview()
functions. That typically worked only once before raising a$rootScope:inprog
error, and also smells like bad practice. - Finally, getting more desperate, I tried
if (!$scope.$$phase) $scope.$apply()
, just to see if it would solve the problem, despite being a terrible practice. Unsurprisingly it also failed just like #4.
The Code
In my controller I have the following function:
$scope.editPhoto = function(img, key, currentIndex) {
var index = currentIndex;
var photo = img;
var apiKey = key;
var ImgID = angular.element('#image-' + photo.id).children().first();
var ImgSrc = ImgID.attr('src');
if(!$scope.featherEditor) {
$scope.featherEditor = new Aviary.Feather({
apiKey: angular.element('#view_photo').attr('key'),
appendTo: angular.element('#view_photo'),
enableCORS: true,
displayImageSize: true,
showWaitIndicator: true,
onLoad: function() {
launchEditor(ImgID, ImgSrc);
},
onReady: hidePreview(),
onSave: function(imageID, newURL) {
angular.element(photo).css('background-image','url("' + newURL + '")');
$http.put('/photos/' + photo.id + '.json',{image: newURL}).then(function(resp){
$scope.results[index] = resp.data.photo;
photosAPI.resizeColumns();
$scope.featherEditor.close();
});
},
onClose: function(isDirty) {
showPreview();
},
onError: function(errorObj) {
alert('Oops! There seems to have been a problem with the Image Editor! Please let us know if the issue persists!');
console.log('APIErrorCode: ' + errorObj.code);
console.log('APIErrorMessage: ' + errorObj.message);
console.log('APIErrorArgs: ' + errorObj.args);
showPreview();
}
});
} else {
$scope.featherEditor.launch({
image: ImgID,
url: ImgSrc
});
}
function launchEditor(id, src) {
$scope.featherEditor.launch({
image: id,
url: src
});
return false;
};
function showPreview() {
$scope.editorOpen = false;
angular.element('#close').show()
};
function hidePreview() {
$scope.editorOpen = true;
angular.element('#close').hide()
};
};
In my view I have the following div, which lives in a modal:
<div id="view_photo">
<div ng-show="!editorOpen">
<div class="photo-preview" id="{{'image-' + results[currentIndex].id}}" ng-style="{'background-image': 'url(' + results[currentIndex].original_image_url + ')'}"></div>
<div class="photo-controls">
<div class="btn btn-default pull-left" style="margin-right:5px;" ng-click="editPhoto(results[currentIndex], '<%= ENV['ADOBE_CLIENT_ID'] %>', currentIndex)">
<i class="fa fa-magic"></i> Edit
</div>
</div>
</div>
</div>