I have a code that is responsible for opening an image loaded in a drag and drop field (dropzone.js) in a modal window for cropping using cropper.js. The code works halfway. The modal window opens, but the buttons inside the modal window do not work. An error is appeared. "Uncaught TypeError: Cannot read property 'cropper' of null". How can this problem be solved? Here is the code.
<script type="text/javascript">
Dropzone.autoDiscover = false;
var c = 0;
var cropped = false;
var myDropzone = new Dropzone('div#myDropzone', {
url: "/plugins/dropzone/dist/upload.php",
addRemoveLinks: true,
createImageThumbnails: true,
autoProcessQueue: false
});
myDropzone.on('addedfile', function(file) {
if (!cropped) {
myDropzone.removeFile(file);
cropper(file);
} else {
cropped = false;
var previewURL = URL.createObjectURL(file);
var dzPreview = $(file.previewElement).find('img');
dzPreview.attr("src", previewURL);
}
});
var cropper = function(file) {
var fileName = file.name;
var loadedFilePath = getSrcImageFromBlob(file);
// @formatter:off
var modalTemplate =
'<div class="modal fade" tabindex="-1" role="dialog">' +
'<div class="modal-dialog" role="document">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-label="Close"><i class="fa fa-times" aria-hidden="true"></i></button>' +
'</div>' +
'<div class="modal-body">' +
'<div class="cropper-container">' +
'<img id="img-' + c + '" src="' + loadedFilePath + '" data-vertical-flip="false" data-horizontal-flip="false">' +
'</div>' +
'</div>' +
'<div class="modal-footer">' +
'<button type="button" class="btn btn-warning rotate-left"><span class="fa fa-rotate-left"></span></button>' +
'<button type="button" class="btn btn-warning rotate-right"><span class="fa fa-rotate-right"></span></button>' +
'<button type="button" class="btn btn-warning scale-x" data-value="-1"><span class="fa fa-arrows-h"></span></button>' +
'<button type="button" class="btn btn-warning scale-y" data-value="-1"><span class="fa fa-arrows-v"></span></button>' +
'<button type="button" class="btn btn-warning reset"><span class="fa fa-refresh"></span></button>' +
'<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>' +
'<button type="button" class="btn btn-primary crop-upload">Crop & upload</button>' +
'</div>' +
'</div>' +
'</div>' +
'</div>';
// @formatter:on
jQuery(modalTemplate).modal('show').on("shown.bs.modal", function() {
var $image = $('#img-' + c);
console.log($image);
var cropper = $image.cropper({
autoCropArea: 1,
aspectRatio: 9 / 16,
cropBoxResizable: false,
movable: true,
rotatable: true,
scalable: true,
viewMode: 2,
minContainerWidth: 250,
maxContainerWidth: 250
})
.on('hidden.bs.modal', function() {
$image.cropper('destroy');
});
$cropperModal.on('click', '.crop-upload', function() {
// get cropped image data
$image.cropper('getCroppedCanvas', {
width: 160,
height: 90,
minWidth: 256,
minHeight: 256,
maxWidth: 4096,
maxHeight: 4096,
fillColor: '#fff',
imageSmoothingEnabled: false,
imageSmoothingQuality: 'high'
}).toBlob(function(blob) {
var croppedFile = blobToFile(blob, fileName);
croppedFile.accepted = true;
var files = myDropzone.getAcceptedFiles();
for (var i = 0; i < files.length; i++) {
var file = files[i];
if (file.name === fileName) {
myDropzone.removeFile(file);
}
}
cropped = true;
myDropzone.files.push(croppedFile);
myDropzone.emit('addedfile', croppedFile);
myDropzone.createThumbnail(croppedFile); //, width, height, resizeMethod, fixOrientation, callback)
$cropperModal.modal('hide');
});
})
.on('click', '.rotate-right', function() {
$image.cropper('rotate', 90);
})
.on('click', '.rotate-left', function() {
$image.cropper('rotate', -90);
})
.on('click', '.reset', function() {
$image.cropper('reset');
})
.on('click', '.scale-x', function() {
if (!$image.data('horizontal-flip')) {
$image.cropper('scale', -1, 1);
$image.data('horizontal-flip', true);
} else {
$image.cropper('scale', 1, 1);
$image.data('horizontal-flip', false);
}
})
.on('click', '.scale-y', function() {
if (!$image.data('vertical-flip')) {
$image.cropper('scale', 1, -1);
$image.data('vertical-flip', true);
} else {
$image.cropper('scale', 1, 1);
$image.data('vertical-flip', false);
}
});
});
};
function getSrcImageFromBlob(blob) {
var urlCreator = window.URL || window.webkitURL;
return urlCreator.createObjectURL(blob);
}
function blobToFile(theBlob, fileName) {
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
}
</script>
Make sure $image
is initialized outside of on("shown.bs.modal", function() {
function
Working example
var dropzone = new Dropzone('div#dropzone', {
url: "/plugins/dropzone/dist/upload.php",
addRemoveLinks: true,
createImageThumbnails: true,
autoProcessQueue: false
});
dropzone.on('addedfile', function(file) {
dropzone.removeFile(file);
cropper(file);
});
$(function() {
fetch("https://i.picsum.photos/id/539/200/300.jpg")
.then(response => response.blob())
.then(blob => {
cropper(blob);
})
})
function cropper(file) {
const url = URL.createObjectURL(file);
var modalTemplate = `<div class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
</div>
<div class="modal-body">
<img id="img" src="${url}" data-vertical-flip="false" data-horizontal-flip="false">
</div>
<div class="modal-footer">
<button class="rotate-right">Rotate Right</button>
</div>
</div>
</div>
</div>`
var $cropperModal = $(modalTemplate);
var $image = null;
$cropperModal.on("shown.bs.modal", function() {
$image = $('#img');
var cropper = $image.cropper({
autoCropArea: 1,
aspectRatio: 9 / 16,
cropBoxResizable: false,
movable: true,
rotatable: true,
scalable: true,
viewMode: 2,
minContainerWidth: 250,
maxContainerWidth: 250
});
}).on('click', '.rotate-right', function() {
$image.cropper('rotate', 90);
}).on('hidden.bs.modal', function() {
$(this).remove();
$image.cropper('destroy');
})
.modal({show: true})
}
img {
display: block;
max-width: 100%;
}
#dropzone {
height: 100px
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.7/cropper.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.7.0/basic.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.7.0/dropzone.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropzone/5.7.0/dropzone.js"></script>
<script>window.Dropzone.autoDiscover = false;</script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cropperjs/1.5.7/cropper.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-cropper@1.0.1/dist/jquery-cropper.min.js"></script>
<div id="dropzone" class="dropzone"></div>