-->

AngularJS POSTs empty requests?

2019-05-25 03:37发布

问题:

I'm a newbie in AngularJS and I've faced an issue when I try to make a POST request with AngularJS and it POSTs no parameters with it. I use Sinatra as a RESTful interface.

That's how my Sinatra backend looks:

post '/layer/:layer_id' do
  @layer = PageLayer.where(id: params[:layer_id]).first
  @layer.content = params[:content]
  @layer.save
end

If try to POST with Postman chrome extension - it works! Sinatra saves the content properly. So I'm sure that the backend works as it should.

That's how my angular test code looks:

TestCtrl = ($scope, $routeParams, $http, $resource) ->
    $scope.layer = []

    Layer = $resource('/layer/:id', {id:'@id'})

$scope.layer = Layer.get {id: $routeParams.layerId}, ->
    console.log "Got you!"

$scope.saveContent = ->
    $scope.layer.$save()
    console.log "Saved!"

angular.module('appDirectives', []).directive "test", ->
    return (scope, element, attrs) ->
        element.bind "blur", ->
            console.log("blur!")
            scope.saveContent()

And HTML-code:

<div>Content: {{layer.content}}</div>

<div>
    <form>
        <input type="text" test ng-model="layer.content">
    </form>
</div>

So, the only question is: What's wrong? Why I can make correct request with Postman but not with angularJS? Angular returns empty "content" so Sinatra saves it as "" every time.

I've also attached a structure of a layer:

g {id: 27245, page_id: 2302, external_id: 26518, original_upload: null…}
content: "dfgdfg"
external_id: 26518
id: 27245
layerNumber: 8
page_id: 2302

How can I log what exactly angular POSTs?

回答1:

Hey this is the exact problem I was having, and the answer now seems so obvious. I knew Angular was sending json, but no matter what I tried it wasn't working. This led me in the right direction, but as for parsing json I had to write

ng_params = JSON.parse(request.body.read)

I had to change 'string' to 'read'. Maybe I have a newer version of the json gem or something. My full save process is like this:

post '/api/v1/test' do
  ng_params = JSON.parse(request.body.read)
  @foo = Foo.new(ng_params)
  if @foo.save
    puts "Page Saved"
    content_type :json
    rabl :foos, format: "json"
  end
end

I use rabl to format the json to have control over what json data Sinatra sends back (no emails or passwords please)

My Angular code is just this (have not yet implemented put, patch or delete, nor auto update of data just yet. You still have to refresh the page to see the new post.) And to be clear, I have a table named 'foos', where the ActiveRecord model is 'Foo', and one column named 'anything' (other than timestamps and id, which I make sure are always there).

// app declaration
var app = angular.module("App", ['ngResource']);

// data service
app.factory('Foo', ['$resource', function($resource) {
  return $resource('/api/v1/test/:id', {id: '@id'});
}]);

// the controller
app.controller('Controller', function($scope, Foo) {

  $scope.foos = Foo.query();

  $scope.create = function(anything) {
    Foo.save({anything: anything}, function(foo){
      $scope.foos.push(foo);
    });
  };
});

Then in my markup the form looks like this, where the important thing is the call to 'create' with 'anything' as the argument in 'ng-submit'. If you have more than one column in your table you call 'create' with more than one argument ex. 'create(anything, bar)'.

<h3>Add something new</h3>
<form ng-submit="create(anything)">
  <input ng-model="anything" type="text">
  <button type="submit">Do it</button>
</form>

While displaying the data is

<li ng-repeat="foo in foos">
  <p>{{foo.anything}}</p>
</li>


回答2:

This link solved the problem. Just add

gem 'rack-parser'

to your Gemfile and add this code to config.ru. Will work like a charm.

require 'rack/parser'
use Rack::Parser, content_types: {
  'application/json' => Proc.new {|body| JSON.parse body }
}


回答3:

All right, I've solved the issue. Somehow Sinatra was not properly getting POSTs from Angular and was not automatically putting them into params. So if we parse the request manually - it works. Like that:

post '/layer/:layer_id' do
  @updated_layer = JSON.parse(request.body.string)
  @layer = PageLayer.where(id: params[:layer_id]).first
  @layer.content = @updated_layer['content']
  @layer.save 
end