Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'Unexpected token' in AJAX upload of multipart/form-data in angular.js 1.3.0

The following code for texture upload was working in angularjs 1.2.26 but stopped working when I upgraded my web application to 1.3.0.

HTML Code

<input file-model="file" name="file" type="file">

fileModel Directive

app.directive('fileModel', [ '$parse', function($parse) {
    return {
        restrict : 'A',
        link : function(scope, element, attrs) {
            var model = $parse(attrs.fileModel);
            var modelSetter = model.assign;

            element.bind('change', function() {
                scope.$apply(function() {
                    modelSetter(scope, element[0].files[0]);
                });
            });

            scope.$on("reset", function() {
                element.val(null);
            });

        }
    };
} ]);

Upload Function - In 1.2.26 choosing "multipart/form-data" as Content-Type would not work. But with "undefined" as Content-Type angular would do some kind of magic that would make it work.

var upload = function(textureUploadUrl) {
        var formData = new FormData();
        formData.append('name', $scope.name);
        formData.append('file', $scope.file);

        $http.post(textureUploadUrl, formData, {
            transformRequest : angular.identity,
            headers : {
                'Content-Type' : undefined
            }
        }).success(function(uploadedTexture) {
            console.log(uploadedTexture);

            // further processing of uploadedTexture
        });
}

ERROR:

SyntaxError: Unexpected token h
    at Object.parse (native)
    at fromJson (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js:1104:14)
    at defaultHttpResponseTransform (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js:8572:18)
    at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js:8517:12
    at forEach (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js:335:20)
    at transformData (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js:8516:3)
    at transformResponse (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js:9224:23)
    at processQueue (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js:12914:27)
    at https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js:12930:27
    at Scope.$eval (https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0/angular.js:14123:28) 

Does anyone know how to get this working in the new version?

UPDATE

I've narrowed down the problem a little bit. It does not work with 1.3.0-rc.5, but with the previous version (rc.4) it does work. So, I'm currently trying to figure out which changes lead to my problem. Here is the changelog.

like image 850
Jonas Avatar asked Oct 17 '14 14:10

Jonas


1 Answers

The problem was in the response header of my texture upload request on server side. For building my application I used Spring MVC and had a request mapping like that, but without the produces specification:

@RequestMapping(value = "/uploadUrl", method = RequestMethod.POST, produces = "text/plain; charset=utf-8")
@ResponseBody
public String textureUploadPOST(HttpServletRequest req) {
    // upload texture and create serveUrl for the texture
    return serveUrl;
}

So, without specifying text/plain as Content-Type, Spring automatically uses application/json as Content-Type. And this causes angular.js to invoke JSON.parse since 1.3.0-rc.5 (change). My texture upload returns an URL pointing to the location where the image is served. Because this is a plain String, it resulted in the described error message. So, don't forget to specify correct Content-Types in your server responses :-)

like image 168
Jonas Avatar answered Oct 07 '22 01:10

Jonas