1

Got an odd problem with angular. I can get this to work with ng-click but I need to use onchange for other reasons.

My code seems to be working fine for other buttons that can be pressed to trigger the same code but when it comes to my upload button it decides not to update the ng-class even though scope.slideMenu is actually logged out as true.

I would also like to close the menu when the user has finished choosing an image/file if someone could help with that as well.

Heres the code:

HTML

                <div class="app-slide-menu"
                     ng-class="{'app-menu-active': slideMenu}">

                    <form class="app-set-image-file-form">
                        <label class="app-file-input"
                               title="Upload Image">
                            <i class="icon-enter"></i>
                            <input type="file"
                                   onchange="angular.element(this).scope().setImageFile(this)"
                                   accept="image/*">
                        </label>
                    </form>
                </div>

Now for the JS:

        scope.setImageFile = function (element) {
        var reader = new FileReader();

        // Converts the image to a data URL.
        reader.readAsDataURL(element.files[0]);
        scope.slideMenuToggle();

        /**
         * When chosen image is selected it triggers the onload function to pass the image to the whiteboardService.
         * @param event - Saves the event of the input field to get the images data URL.
         */
        reader.onload = function (event) {
            fabric.Image.fromURL(event.target.result, function (img) {
                whiteboardService.uploadImageToCanvas(img);
            });

            // Resets the form that wraps round the file input to allow the
            // user to add more than one of the same file.
            // NOTE: This will break other inputs if you put them inside this form
            $('.app-set-image-file-form').trigger('reset');
        };
    };

And the simple toggle JS:

    scope.slideMenuToggle = function () {
        scope.slideMenu = !scope.slideMenu;
    };
4
  • 3
    Are you sure you don't want to use ng-change ? Commented Mar 10, 2016 at 17:33
  • ngModel doesn't work with input type file and ngChange ALWAYS requires ngModel. Commented Mar 10, 2016 at 17:45
  • Have you tried triggering a $digest cycle after your changes? Angualr doesn't know anything has changed since you need to use the onchange handler instead of ng-change. You can trigger using $timeout or $scope.$apply Commented Mar 10, 2016 at 18:18
  • FYI this explains why we can't use Ng-change stackoverflow.com/questions/17922557/… Commented Mar 11, 2016 at 11:17

3 Answers 3

1

Use ngChange. onChange is still the JavaScript onChange it was before using Angular. When you use onChange, Angular doesn't know things have changed.

This is one of the rare cases calling $scope.$apply() would be needed (when using onChange)

Sign up to request clarification or add additional context in comments.

2 Comments

Oddly Scope.apply doesn't work. If I put this in the function that is being called on change. scope.slideMenu = true; scope.$apply(); am I doing this wrong. Please note that my scope doesn't need the $ as the developer before us thought it would of been a good idea......
Update you can use scope.apply() but oddly you have to write it after everything else
0

I think your best option would be to create an angular directive for a custom onchange, something like this:

app.directive('customOnChange', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            var onChangeHandler = scope.$eval(attrs.customOnChange);
            element.bind('change', onChangeHandler);
        }
    };
});

Then you can use it like this on your input: <input type="file" custom-on-change="setImageFile" accept="image/*">

Finally in your controller, you can do this:

$scope.setImageFile = function (element) {
    var reader = new FileReader();

    // Converts the image to a data URL.
    reader.readAsDataURL(element.files[0]);
    scope.slideMenuToggle();

    /**
     * When chosen image is selected it triggers the onload function to pass the image to the whiteboardService.
     * @param event - Saves the event of the input field to get the images data URL.
     */
    reader.onload = function (event) {
        fabric.Image.fromURL(event.target.result, function (img) {
            whiteboardService.uploadImageToCanvas(img);
        });

        // Resets the form that wraps round the file input to allow the
        // user to add more than one of the same file.
        // NOTE: This will break other inputs if you put them inside this form
        $('.app-set-image-file-form').trigger('reset');
    };
};

Hope this can help.

2 Comments

Going to give this a go
Not too sure why but this isn't triggering my function
0

Ok guys,

Sorry to say that your suggestions didn't help me but I managed to come to a solution that fixed my bug but I don't really understand why so please let me know if you can let me know.

I've basically added a class of 'js-input-file' to the input tag and then put this code below to trigger a scope reset.

        var inputScope = angular.element('.js-input-file').scope();

        inputScope.$apply();

This fixes my problem but I just can't get round my head why putting scope.$apply(); on its own doesn't fix the problem but the above does. Let me know your thoughts.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.