Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

x-www-form-urlencoded and $resource #1937

Closed
edgeonetechnologies opened this issue Feb 1, 2013 · 11 comments
Closed

x-www-form-urlencoded and $resource #1937

edgeonetechnologies opened this issue Feb 1, 2013 · 11 comments

Comments

@edgeonetechnologies
Copy link

My backend is PHP and I followed this guide
http://victorblog.com/2012/12/20/make-angularjs-http-service-behave-like-jquery-ajax/

app.config(function($httpProvider) {

    // Use x-www-form-urlencoded Content-Type
    $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';

    // Override $http service's default transformRequest
    $httpProvider.defaults.transformRequest = [function(data)
    {
        return angular.isObject(data) && String(data) !== '[object File]' ? jQuery.param(data) : data;
    }];

}); 

This allows me to use $http.post to sent POST data to my server.
Without doing this PHP cannot even see any POST data since it has no idea how to parse a JSON object.

$http.post works fine as in the example below

$http.post('ajax/campaigns/123', {id: '123', 'title':'test title'});

What I am having issues with is with $resource.
After following that guide and trying to run the following code

.factory('Campaign', function($resource) {
    return $resource('ajax/campaigns/:id', {id:'@id'});
})
var updatedCampaign = new Campaign({
    id: 123,
    title: "test title"
});

updatedCampaign.$save(function(saveData) { });

When I run the save function, it freaks out and tries to make many requests: GET, POST, GET, DELETE, DELETE, POST

It should be making a single POST request. It seems like it is running through many of the possible functions of a $resource object.

Has anyone had success using a $resource to send POST data to a PHP backend or am I missing something here?

@BrynCooke
Copy link

I have used the following against master:

angular.module('restServices', [ 'ngResource' ])
.factory('UserWs', function($resource) {
    return $resource('/webBase/ws/user', {}, {
        login : {
            method : 'POST',
            url : '/webBase/ws/user/login',
            headers : {'Content-Type': 'application/x-www-form-urlencoded'}
        }
    })
})

And then in the controller:

function LoginCtrl($scope, UserWs) {
        $scope.user = null;
        $scope.login = function() {
            UserWs.login($.param({
                username : $scope.username,
                password : $scope.password,
            })});
        };
    };

Note the use of $.param as the object will not automatically convert to a url encoded string (though I think it should).

@RomaLefrancois
Copy link

You can setup the $httpProvider of your app to have x-www-form-urlencoded as default content type for POST request.

    .config(function($httpProvider) {
        $httpProvider.defaults.headers.post  = {'Content-Type': 'application/x-www-form-urlencoded'};
    });

@calmera
Copy link

calmera commented Mar 29, 2013

I currently have the same issue. What really happens is the $.param operation will run through all properties of you object. Resource objects have $get, $delete and other properties as well, in which case the property is invoked and the result is being used as the parameter value:

From their code:

// If value is a function, invoke it and return its value
value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );

I'm trying now to clone the data object, removing all properties starting with a $ and using that to pass to the $.param function. I'll let you know if it works.

@calmera
Copy link

calmera commented Mar 29, 2013

Ok, this seems to work:

Use the following code for your transformRequest:

$httpProvider.defaults.transformRequest = function(data) {
    if (data === undefined) return data;

    var clonedData = clone(data);
    for (var property in clonedData)
        if (property.substr(0, 1) == '$')
            clonedData[property] = null;

    return $.param(clonedData);
};

@btford btford closed this as completed Aug 24, 2013
@btford
Copy link
Contributor

btford commented Aug 24, 2013

As part of our effort to clean out old issues, this issue is being automatically closed since it has been inactivite for over two months.

Please try the newest versions of Angular (1.0.8 and 1.2.0-rc.1), and if the issue persists, comment below so we can discuss it.

Thanks!

@far-out
Copy link

far-out commented Dec 21, 2013

As of Angular 1.2.5, this is still an issue.

To add onto calmera's response, I found using "delete" on the property to be the most effective:

$httpProvider.defaults.transformRequest = function(data) {
    if (data === undefined) return data;

    var clonedData = clone(data);
    for (var property in clonedData)
        if (property.substr(0, 1) == '$')
            delete clonedData[property];

    return $.param(clonedData);
};

petebacondarwin pushed a commit that referenced this issue Feb 4, 2015
petebacondarwin pushed a commit that referenced this issue Feb 4, 2015
@vivex
Copy link

vivex commented Jun 14, 2015

Thanks @far-out Following code worked well for me-

In app config -

$httpProvider.defaults.transformRequest = function (data) {
        if (data === undefined)
            return data;
        var clonedData = $.extend(true, {}, data);
        for (var property in clonedData)
            if (property.substr(0, 1) == '$')
                delete clonedData[property];

        return $.param(clonedData);
    };

With your resource request -

 headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }

@NKjoep
Copy link

NKjoep commented Jun 16, 2015

With the trick from @far-out and @vivex, does exist a way to make coexist the two behaviors?

I need to send json as default and standard www-form-urlencoded sometimes.

@healqq
Copy link

healqq commented Aug 4, 2015

@NKjoep Angular allows to set transformRequest and contentType header for a specific request. Just create your own action in $resourse declaration.

var photosResource = $resource(
    'url/:id', 
    {id:'@id'},
    {
        save:{
            method: 'POST',
            transformRequest: _transformFormDataRequest,
            headers: {
                'Content-type': ''application/x-www-form-urlencoded
            }
        }
    }
);

@davidwillianx
Copy link

Thx!!!! @BrynCooke your sample works perfect 👍

@iolufemi
Copy link

Thanks @vivex , It worked for me too

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests