how to fix this AngularJS JCrop directive?
Asked Answered
D

2

2

I'm trying to use JCrop with AngularJS. I have the following directive that I need help to fix a bit:

.directive('imgCropped', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: { src:'@', selected:'&' },
        link: function(scope,element, attr) {
            var myImg;
            var clear = function() {
                if (myImg) {
                    myImg.next().remove();
                    myImg.remove();
                    myImg = undefined;
                }
            };
            scope.$watch('src', function(nv) {
                clear();
                if (nv) {
                    element.after('<img />');
                    myImg = element.next();
                    myImg.attr('src',nv);

                    $(myImg).Jcrop({
                        trackDocument: true,
                        onSelect: function(x) {
                            /*if (!scope.$$phase) {
                                scope.$apply(function() {
                                    scope.selected({cords: x});
                                });
                            }*/
                            scope.selected({cords: x});
                        },
                        aspectRatio: 1,
                        boxWidth: 400, boxHeight: 400,
                        setSelect: [0, 0, 400, 400]
                    });
                }
            });

            scope.$on('$destroy', clear);
        }
    };
})

the problem is that JCrop doesn't detect the true image size correctly and I need to add a trueSize option, the only way that I know how to do is to wrap the Jcrop invocation in a callback, looks pretty nasty.

also, if I use scope.$apply in the onSelect callback I get the $digest already in progress error. why is that ?

EDIT: I can successfully get the true image size with the following code, but there must be a better way to do so

.directive('imgCropped', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: { src:'@', selected:'&' },
        link: function(scope,element, attr) {
            var myImg;
            var clear = function() {
                if (myImg) {
                    myImg.next().remove();
                    myImg.remove();
                    myImg = undefined;
                }
            };
            scope.$watch('src', function(nv) {
                clear();
                if (nv) {
                    element.after('<img />');
                    myImg = element.next();
                    myImg.attr('src',nv);

                    var temp = new Image();
                    temp.src = nv;
                    temp.onload = function() {
                        var width = this.width;
                        var height = this.height;

                        $(myImg).Jcrop({
                            trackDocument: true,
                            onSelect: function(x) {
                                /*if (!scope.$$phase) {
                                 scope.$apply(function() {
                                 scope.selected({cords: x});
                                 });
                                 }*/
                                scope.selected({cords: x});
                            },
                            aspectRatio: 1,
                            boxWidth: 400, boxHeight: 400,
                            setSelect: [0, 0, 400, 400],
                            trueSize: [width, height]
                        });
                    }
                }
            });

            scope.$on('$destroy', clear);
        }
    };
})
Dissension answered 24/1, 2013 at 15:3 Comment(5)
Do you have a plunker or jsfiddle of what isn't working? I am actually using JCrop with Angular, however not like this.. my img src doesn't change so I'm just using an attribute directive on an img tag.Unanimous
I created a plunkr - plnkr.co/edit/phXrGBxpPY7DZjkQmGXd - in the plunkr its working perfectly (I put a huge image on purpose). in my app it doesn't work and the wrong image dimensions are detected. is it possible that some css rule is styling the image and it cause this ?Dissension
CSS rules shouldn't effect the Image object way of loading an image.Unanimous
I guess I don't understand your question. Originally your question was "Is there a better way to do this?" and you were doing with a DOM element... which I answered. Now the question includes my answer but is still asking if there's a better way to do it? Because you don't like nested callbacks? What is your question really?Unanimous
my question is, in plunkr it seems to be working fine (without the temp image) and JCrop is detecting the correct image size. but when I'm using it in my app the wrong image size is detected and I need to use that temp image. what can cause that ?Dissension
U
1

What you're doing is probably fine. The directive looks okay. As far as getting the image size, you can do it with straight JavaScript like so:

var img = new Image();
img.onload = function () {
   var w = img.width,
       h = img.height;
   //do what you need to do here.
};
img.src = 'somefile.gif';

It will save you the DOM manipulation.

Unanimous answered 24/1, 2013 at 16:1 Comment(3)
this is what I added in the EDIT part of the question. looks pretty ugly to put the JCrop statement inside a callbackDissension
Heh... well, welcome to JavaScript. You can always bust your callback functions out into their own declarations, rather than having nested anonymous functions. One tip I do have for you though is this: you have a watch on your directive's scope.src, but you never update it, and you're populating it with a one-way binding "@" rather than a two way binding "=". Something to be aware of.Unanimous
That's what I'm saying.. you're actually doing that in an odd way... rather than have src="{{image}}" and src: "@" , you could do src="image" and src: "=". I suppose either way works as long as you're never trying to push the change back the other direction.Unanimous
D
0

I'm working on a directive that I'll be pushing to bower (after a few more fixes):

angular-image-crop

working demo

In the constructor callback, I call this.getBounds() and then I apply those values to the cords in onSelect:

https://github.com/coolaj86/angular-image-crop/blob/master/app/scripts/controllers/profile-pic.js#L24

Direful answered 12/5, 2014 at 14:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.