Jonas
Jonas

Reputation: 1345

'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.

Upvotes: 8

Views: 2573

Answers (1)

Jonas
Jonas

Reputation: 1345

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 :-)

Upvotes: 14

Related Questions