fengyuanchen / cropper

⚠️ [Deprecated] No longer maintained, please use https://github.com/fengyuanchen/jquery-cropper
MIT License
7.75k stars 1.74k forks source link

Uncaught TypeError: Cannot read property 'toDataURL' of null when next time trying to crop #1010

Closed ajitdas123 closed 6 years ago

ajitdas123 commented 6 years ago

I am using jquery cropper to achieve something like this below. Whenever the user clicks on an input that image will be sent to cropper canvas. And once the user saves the cropped image it will be loaded into the preview box and clear the cropper canvas.

This is what I am trying to achieve enter image description here

But the problem with this is, this works great for the first input file. But when I try to do the same with next input it through

Uncaught TypeError: Cannot read property 'toDataURL' of null

I could not figure out why this is happening when it works great for the first time.

My code is here below.

$(document).ready(function() {
  $('Input[type="file"]').on('change', function(event) {
    var parent = $(this).closest('div');
    parent.addClass('isSelected');
    cropImage(URL.createObjectURL(event.target.files[0]), parent);
  })

})

function cropImage(blob, domElement) {
  var output = document.getElementById('change-profile-pic');
  output.src = blob;
  $('#change-profile-pic').cropper('destroy');
  var $croppedImage = $('#change-profile-pic')
  var result;
  result = $croppedImage.cropper({
    ready: function() {
      console.log('Cropper initialized');
    },
    aspectRatio: 1 / 1,
    crop: function(e) {}
  })

  $('#save').click(function(action) {
    domElement.find('img').attr('src', $croppedImage.cropper('getCroppedCanvas').toDataURL());
    domElement.removeClass('isSelected');

    result.cropper('destroy');
  })
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="row mt-5">
  <div class="col-6">
    <div class="image-wraper">
      <input type="file" name="image">
      <div class="image-preview">
        <img src="" class="img-fluid">
      </div>
    </div>
    <div class="image-wraper">
      <input type="file" name="image">
      <div class="image-preview">
        <img src="" class="img-fluid">
      </div>
    </div>
    <div class="image-wraper">
      <input type="file" name="image">
      <div class="image-preview">
        <img src="" class="img-fluid">
      </div>
    </div>
  </div>
  <div class="col-6">
    <div class="crop-image-section">
      <img src="" id="change-profile-pic">
    </div>
    <button type="button" id="save" class="btn btn-primary">Save</button>

  </div>
</div>

I added code to the jsFiddle here

Can anyone please tell me where I m doing wrong. Thanks

fengyuanchen commented 6 years ago

Be sure the Cropper instance is ready and still there when you call it later.

ajitdas123 commented 6 years ago

@fengyuanchen , yes cropper is getting initialized before clicking on save.

If I place the save function inside crop like the code below it works.

result = $croppedImage.cropper({
    ready: function() {
      console.log('Cropper initialized');
    },
    aspectRatio: 1 / 1,
    crop: function(e) {
 $('#save').click(function(action) {
    domElement.find('img').attr('src', $croppedImage.cropper('getCroppedCanvas').toDataURL());
    domElement.removeClass('isSelected');

    result.cropper('destroy');
  })
}
  })

However, after doing it with two, three images it crashes the webpage. :/ Can u please look into this. Thank you

fengyuanchen commented 6 years ago

The crop option is an event shortcut which will be execute many many times, you must use $().once method to bind event handler within it!

Usama4745 commented 4 years ago

The crop option is an event shortcut which will be execute many many times, you must use $().once method to bind event handler within it!

how?