4

I am trying to use Carrierwave with Jcrop in the exact same way as Ryan Bates uses it in RailsCasts Episode 182 (revised) but I just can't get Jcrop to work and I can't figure out why.

When I get to crop.html.erb, it shows the original picture and the preview as expected but I can't select anything on the original picture and the preview is not responding.

I have played around a little bit and when I add the () behind .Jcrop I can at least select something on the original picture but the preview is still not responding and the selected area is also not keeping the aspectRatio of 1. So I guess for some reason the code after .Jcrop is not executed. I am not a CoffeeScript expert so I need some help with figuring this out.

Here is my code. Thanks a lot!

user.js.coffee:

jQuery ->
  new AvatarCropper()

class AvatarCropper
  constructor: ->
    $('#cropbox').Jcrop() ->
      aspectRatio: 1
      setSelect: [0, 0, 500, 500]
      onSelect: @update
      onChange: @update

    update: (coords) =>
      $('#user_crop_x').val(coords.x)
      $('#user_crop_y').val(coords.y)
      $('#user_crop_w').val(coords.w)
      $('#user_crop_h').val(coords.h)
      @updatePreview(coords)

    updatePreview: (coords) =>
      $('#preview').css
        width: Math.round(100/coords.w * $('#cropbox').width()) + 'px'
        height: Math.round(100/coords.h * $('#cropbox').height()) + 'px'  
        marginLeft: '-' + Math.round(100/coords.w * coords.x) + 'px'
        marginTop: '-' + Math.round(100/coords.h * coords.y) + 'px'

users_controller.rb:

  def update
      @user = User.find(params[:id])
      if @user.update_attributes(params[:user])
        if params[:user][:avatar].present?
          render :crop
        else
          redirect_to @user, notice: "Successfully updated user."
        end
      else
        render :new
      end
    end

  def crop
    @user = User.find(params[:id])
    render view: "crop"
  end

users/crop.html.erb:

<h1>Crop Avatar</h1>
<%= image_tag @user.avatar_url(:pre_crop), id: "cropbox" %>

<h4>Preview</h4>
<div style="width:100px; height:100px; overflow:hidden;">
  <%= image_tag @user.avatar.url(:pre_crop), :id => "preview" %>
</div>

<%= form_for @user do |f| %>
  <div class="actions">
    <% %w[x y w h].each do |attribute| %>
      <%= f.hidden_field "crop_#{attribute}"%>
    <% end %>
    <%= f.submit "Crop" %>
  </div>
<% end %>
mu is too short
  • 426,620
  • 70
  • 833
  • 800
fjahr
  • 449
  • 5
  • 25

3 Answers3

4

This isn't what you want:

$('#cropbox').Jcrop ->
  aspectRatio: 1
  setSelect: [0, 0, 500, 500]
  onSelect: @update
  onChange: @update

That calls the Jcrop plugin with a function (->) as its argument and Jcrop doesn't know what to do with a function. Adding parentheses:

$('#cropbox').Jcrop() ->
  aspectRatio: 1
  setSelect: [0, 0, 500, 500]
  onSelect: @update
  onChange: @update

doesn't help that much; that calls the plugin (.Jcrop()) properly but then tries to call its return value as another function that takes a function as an argument:

$('#cropbox').Jcrop()(-> ...)

That let's you play with the cropper but you're probably getting an error unless the Jcrop plugin returns a function; in any case, that doesn't get your options into the Jcrop plugin so your callbacks won't be called and Jcrop won't see aspect ratio.

I think you just want to drop the -> (and not include the parentheses) so that you call the Jcrop plugin with an options object:

$('#cropbox').Jcrop
  aspectRatio: 1
  setSelect: [0, 0, 500, 500]
  onSelect: @update
  onChange: @update

Or you could do it this way if the parentheses help you see the grouping:

$('#cropbox').Jcrop(
  aspectRatio: 1
  setSelect: [0, 0, 500, 500]
  onSelect: @update
  onChange: @update
)

Once that's done, you need to look carefully at your indentation, your AvatarCropper doesn't have update and updatePreview methods because they're indented too far:

class AvatarCropper
  constructor: ->
    $('#cropbox').Jcrop
    ...
    update: (coords) =>
    ...
    updatePreview: (coords) =>

That ends up defining an anonymous object like {update: ..., updatePreview: ...} and then it gets thrown away; this problem would have been more noticeable with a deeper indent (say 4 spaces) or a different editor but I'm not going to belabor that point, suffice to say that you must watch your whitespace very carefully in CoffeeScript; perhaps better compiler warnings would be helpful for this all too common mistake. Fix your indentation and you're all good:

Demo: http://jsfiddle.net/ambiguous/jTvV3/

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • I'm sorry, I should have made that more clear but the way with just .Jcrop is the way I used initially because that was the way Ryan Bates did it but that didn't work at all. It just shows the picture but I can't select anything. Same with the parentheses around the group. – fjahr May 04 '12 at 12:47
  • yeah, in my application.js I have: – fjahr May 04 '12 at 16:27
  • //= require jquery //= require jquery_ujs //= require jquery.Jcrop //= require_tree . – fjahr May 04 '12 at 16:28
  • I think the fact that I can at least select a area when I add the parentheses points to that it's not a problem with the asset pipeline. – fjahr May 04 '12 at 16:30
  • @FabianJahr: Welcome to the world of significant whitespace and compilers that aren't smart enough to complain about obvious mistakes, have a look at my update. – mu is too short May 04 '12 at 17:25
  • Thanks, I fixed the indentation but unfortunately it's still not working, even when I use the snipped you posted. On the crop page I get the error: Uncaught ReferenceError: coords is not defined. – fjahr May 09 '12 at 20:12
  • What specifically is triggering that error? Can you reproduce it using the jsfiddle.net demo? – mu is too short May 09 '12 at 20:20
  • correction: I just pasted the exact code from the railscast into my user.js.coffee and now the coords error is gone but jcrop is still not working. – fjahr May 09 '12 at 20:43
  • You probably have a whitespace problem or you didn't paste the exact code. Reproduce your problem on jsfiddle.net or I can't help you. – mu is too short May 09 '12 at 21:11
1

if you are using bootstrap you have to add

img.jcrop {max-width: none}

for your css.. somehow bootstrap is overriding img {max-width:100%}

for more information checkout https://github.com/twbs/bootstrap/issues/1649

user1567004
  • 175
  • 1
  • 8
0

Rather than using js.coffee , put the code in js file while i have put in application.js and worked like a charm

function showCoords(c) {
$('#user_crop_x').val(c.x);
$('#user_crop_y').val(c.y);
$('#user_crop_w').val(c.w);
$('#user_crop_h').val(c.h); };


   jQuery(function($) {
    $('#target').Jcrop({
        onSelect:    showCoords,
        bgColor:     'magenta',
        bgOpacity:   .4,
        setSelect:   [ 0, 0, 600, 600 ],
        aspectRatio: 1
    });
});

please refer the link if error persists