AngularJS POSTs empty requests? - javascript

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?

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>

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 }
}

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

Related

problems displaying JSON Data with Angular Js ng-repeat

I am able to retrieve following JSON data (test data) from a php file :
JSON:
[{"id":"1","name":"shabri","desc":"bbkbjkbjbjnnklnln","location":"location","mobile":"498534534","telephone":"4549385","offer":"20","email":"nfnkjrnfnrndnrgnkjr"},{"id":"2","name":"bhagatfergdfgfdg","desc":"vfdgfdbgbbgbg","location":"fbgbgfbgfb","mobile":"544656757","telephone":"4223424","offer":"30","email":"vdsxdvgvgv"},{"id":"3","name":"rddfdgdf","desc":"bdffgd","location":"fghgfhfhgf","mobile":"8598","telephone":"856845","offer":"6","email":"httrdh6kiki"}]
Angular Js Controller
.controller('RestaurantsCtrl', ['$scope', '$http', function ($scope, $http) {
$http.get('http://xyz/getRestros.php')
.success(function(data) {
alert(data);
$scope.Restaurants = data;
});
}])
I am sure that JSON data is retrieved because for testing i have alert(data) which displays correct json encoded data in the alert box.
Issue is that data is not getting assigned to $scope.Restaurants. so ng-repeat in html is not populating the list.
ng-repeat populates the list if i hard code $scope.Restaurants.
what's the mistake here ? please help..
EDIT:
hard coded $scope.Restaurants that works:
$scope.Restaurants = [
{ name: 'Shabri', id: 1 },
{ name: 'Bhagat Tarachand', id: 2 },
{ name: 'Udipi', id: 3 },
{ name: 'Shahu', id: 4 },
{ name: 'Bagdadi', id: 5 },
{ name: 'Shiv Sagar', id: 6 }
];
ng-repeat:
<a class="item item-thumbnail-left" ng-repeat="Restaurant in Restaurants | filter: searchText" href="#/app/Restaurants/{{Restaurant.id}}">
<img src="img/default_restro.png" style="margin-top:30px;"/>
<h2 style="font-weight:bold;">{{Restaurant.id}}</h2>
<p>{{Restaurant.name}}</p><br>
<span style="white-space: pre-wrap; font-weight:300;">This is the description about the restaurant click to know more.</span><br>
</a>
You can do debugging in Chrome Developer Tools view (Ctrl-Shift-I) and set breakpoint to see if $scope.Restaurant has value assigned after the line
$scope.Restaurants = data;
You need to parse the returned JSON string into an object.
Try
arrayData = JSON.parse(data);
$scope.Restaurants = arrayData;
It's not actually a answer but i found the root cause of the problem above and might happen with someone.
The free web hosting I was using to host that php file was the culprit.
Everytime that php is executed that web hosting appended some google analytics script at the end after the object ends. That script doesn't appear while live editing that file . i don't know how.
Anyway , i found it when i debugged the $scope.Restaurants again.
It seems that if anything else is echoed with the JSON object thn it would serialize and consider it string.
After correcting and changing the host , difference was spotted and it was considered as actual json objects, and it worked fine.

Get values from link that brought my to the current page

I know - the first thing you're gonna say is "Use the referrer!"
But that'd be the wrong answer, and I'll explain why.
Assume you're on a page, say "Employees", that has a search. The search fields for name yield a table of employees upon submitting. In that table, the Employee Name is a clickable object, in this case a hyperlink. That link goes to an Employee Details page. On that page, there isn't really anything, because that page actually loads up a bunch of Angular data from a subpage.
So, the problem:
On Employees, you click on a link:
http://localhost/EmployeeData#/details/cc30e1f8-b21c-4384-9710-e927686c925c
That link takes you to the EmployeeData controller and index view. The index view loads up details.html, which is an angular happiness full of data. It works great.
But back in the Index view, there's a tiny bit of code that tells the details where to show up, and has a breadcrumb. So in the Index ViewResult, (EmployeeData/Index.aspx), I'd like to be able to pull the GUID from the link that got you there... But when I use the referrer, it just tells me "You came from the Employee Search".
public ViewResult Index()
{
var vm = _vmp.GetViewModel<EmployeeDataViewModel>();
vm.Breadcrumb = CreateBreadCrumbDisplay();
return View(vm);
}
public string CreateBreadCrumbDisplay()
{
var referrer = (Request.UrlReferrer != null) ? Request.UrlReferrer.AbsoluteUri : string.Empty;
var curUrl = Request.ServerVariables["SCRIPT_NAME"];
//do lots of stuff
return theBreadCrumb;
}
In this instance, CreateBreadCrumbDisplay just returns http://localhost/Employee. And curUrl just has "EmployeeData", thanks to all the real data stuff happening in the angular page, and not actually in the Index view.
So, what I need to do is grab the full URL, with the ID, and pass that ID into my "CreateBreadCrumbDisplay" method.
Thoughts?
I think a possible solution would be to grab the URL params with $routeParams and pass it to your CreateBreadCrumbDisplay method from Angular.
If I understand your problem correctly reading up on $routeParams here should solve your problem.
Here is an example of how it should work:
First config your routes in Angular
myApp.config(function($routeProvider) {
$routeProvider.when('/link/:GUID', {
controller: 'SomeCtrl',
templateUrl: 'sometemplate.html'
});
});
Then in your controller
myApp.controller('SomeCtrl', function($scope, $routeParams) {
console.log($routeParams);
});
Link to it from somewhere
foo
And finally the console output:
{ GUID: "cc30e1f8-b21c-4384-9710-e927686c925c" }
As long as I understand , you can use $location service , $location.absUrl(); And you may succeed this in many other ways even passing your url to action method as a parameter while submitting .

How to submit a successful post request using the MEAN stack?

I'm using yeoman to scaffold a project. In the end I want to learn to scaffold the CRUD. I'm getting stuck on a post request. I've picked the angular-fullstack generator because I'm very comfortable with normal angular-generator.
My post request attempts are being hulled by a 400 error while trying to submit a new object to the Things collection. I'm pretty lost, I need to see completed code of a post request using this folder structure.
UPDATE:
The 400 error is gone however, the req.body.
UPDATE2:
Everything is properly working now answers are both in my code and answer.
So, Using the angular-fullstack generator of yeoman, how would I make a post request to create an awesomeThing in the Thing collection of the mongo db.
I'm surely missing something but I think most of the pieces needed to make a POST request successful are presented below. Any direction would be much appreciated.
app/views/partials/main.html
<div class="row marketing">
<div ng-repeat="thing in awesomeThings">
<h4>{{thing.name}}</h4>
<p>{{thing.info}}</p>
</div>
</div>
<form ng-submit="addAwesome()">
<input type="text" ng-model="tempAwesome.name">
<input type="submit" class="btn btn-primary" value="Add">
</form>
app/scripts/controllers/main.html
$scope.name = [];
$http.get('/api/awesomeThings').success(function(awesomeThings) {
$scope.awesomeThings = awesomeThings;
});
$scope.addAwesome = function() {
$http.post('/api/awesomeThings', $scope.tempAwesome).success(function(postData) {
$scope.awesomeThings = postData;
}).error(function(postData, status){
console.log(postData);
$scope.status = status;
console.log(status);
});
};
lib/routes.js
app.route('/api/awesomeThings')
.get(api.awesomeThings)
.post(api.create);
lib/controllers/api.js
mongoose.model('Thing', ThingSchema);
exports.create = function (req, res) {
var awesomeThing = new Thing(req.body);
awesomeThing.save(function(err) {
if (err) return res.json(400, err);
});
};
lib/models/thing.js
var ThingSchema = new Schema({
name: String,
info: String,
awesomeness: Number
});
I have a hunch it is mongoose blocking this because my submission isnt matching the schema? ? any other thoughts?
Edit
Ok one last suggestion based on looking at some other code I have. try this for your post instead
$http.post('/api/awesomeThings' { name : $scope.name })
Edit based on code change
Change your ng-model in your form to.
<input type="text" ng-model="name">
I think this line is failing
var awesomeThing = new Thing(req.body);
what I think is happening is you are sending an object that looks like this in the body
{ tempThing: "sometext" }
when mongoose tries to create your object it dosen't have a property called tempThing so it bails out. This can be overridden by setting {strict:false} on your schema if you like but, if your intention is to set name from your form I would start with change tempThing to name.
Old Answer
I think your /lib/routes.js has a typo. you have a ';' after .get(api.awesomeThings)
that's causing the .post(api.awesomeThings) to be ignored. remove the semicolon and it would probably start working.

AngularJS: Unexpected ngResource get() behaviour

I am trying to fire a simple GET request from my angular app via $resource service (so there is no need to say that I am new to Angular). Since my server side behaves in RESTfull manner, I am trying to use the nice Angular ngResource. Before trying to generate the GET request from my Angular app, I tested the availability of the resource and it returns the expected information when requested.
My service:
services.factory('ScreenInitializer', ['$resource', function($resource) {
return $resource('/angular/screenInitializer/:initializerParameter',
{initializerParameter : '#sectionName'});
}]);
My controller:
app.controller('HomePageController', ['$scope', 'ScreenInitializer', function($scope, ScreenInitializer) {
$scope.searchByOptions = ScreenInitializer.get({sectionName: "homePageSearchBy"});
// Some irrelevant stuff here...
}
My expectation:
According to the book I read and some examples in the net, what I expected is the parameter initilizeParam in the resource URL to be replaced with the argument that I pass to the .get() method and as a result to have a GET request at
localhost:8080/angular/screenInitilizer/homePageSearchBy
What actually happened:
is a GET request where the "homePageSearchBy" is passed as parameter - localhost:8080/angular/screenInitializer?sectionName=homePageSearchBy. Due to that the server responds with 404 - Resource not found. (which is expected since its location is at .../screenInitializer/homePageSearchBy)
My question:
Is my expectation wrong, or I am using ngResource in a bad way?.
Thanks!
From the docs:
If the parameter value is prefixed with # then the value of that parameter is extracted from the data object (useful for non-GET operations).
So this
{initializerParameter : '#sectionName'}
Is irrelevant for GET operations. And this
{sectionName: "homePageSearchBy"}
appends a sectionName parameter because the URL template does not contain sectionName. What you need is
ScreenInitializer.get({initializerParameter : "homePageSearchBy"})
I prefer to new it up, but if you pass an empty object to the get it will work. See below.
$scope.screen = new ScreenInitialize({sectionName: "homePageSearchBy"});
$scope.screen.$get(function(result){ .. do something ..}, function(error){ .. do something ..})
$scope.searchByOptions = ScreenInitializer.get({}, {sectionName: "homePageSearchBy"});
Example plunkr showing the urls (you have to inspect):
http://embed.plnkr.co/kQsMujk9IgGxdxSE2g0E/
Code:
var Screen = $resource(
'/angular/screenInitializer/:initializerParameter',
{initializerParameter : '#sectionName'});
$scope.screen = Screen.get({}, {sectionName: "homePageSearchBy"});
The url this calls:
http://run.plnkr.co/angular/screenInitializer/homePageSearchBy

How to connect and put in JSON instead of mongolab in AngularJS?

I want to use JSON instead of MongoLab example shown on AngularJS website.
Here's the code from the website:
angular.module('mongolab', ['ngResource']).
factory('Project', function($resource) {
var Project = $resource('https://api.mongolab.com/api/1/databases' +
'/angularjs/collections/projects/:id',
{ apiKey: '4f847ad3e4b08a2eed5f3b54' }, {
update: { method: 'PUT' }
}
);
Is there any way I could connect and put into JSON file available on my folder instead of hosting it to MongoLab?
Any response would be really appreciated!
You can look at this example:
Reading in JSON through Angular Resources Service
You want to return the Project variable from your factory
var Project = $resource('test.json', {} );
return Project;
then use it in the controller after you inject it:
Project.get(function(data){
$scope.bar = data.foo;
});
Update:
After looking thru the 1.1.3 angular-resource.js code, it looks like it always does an http request to get its data. Set up a simple RoR app with a REST interface for testing.
Or use plunker (like the linked question above) for complete remote testing.

Categories

Resources