AngularJS: Unexpected ngResource get() behaviour - javascript

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

Related

API Connect - 500 error when including basic Javascript

I'm trying some basic API Connect tutorials on IBM's platform (running locally using loopback) and have got completely stuck at an early point.
I've built a basic API service with some in-memory data and setter / getter functions. I've then built a separate API which takes two GET parameters and uses one of my getter functions to perform a search based on two criteria. When I run it, I successfully get a response with the following JSON object:
[{"itemId":1,"charge":9,"itemSize":2,"id":2}]
I've then tried to add a piece of server logic that modifies the response data - at this point, I'm just trying to add an extra field. I've added a Javascript component in the Assemble view and included the following code (taken from a tutorial), which I thought should modify the message body returned by the API while still passing it through:
//APIC: get the payload
var json = apim.getvariable('message.body');
//console.error("json %s", JSON.stringify(json));
//same: code to inject new attribute
json.platform = 'Powered by IBM API Connect';
//APIC: set the payload
//message.body = json;
apim.setvariable('message.body', json);
Instead of getting an extra JSON parameter ("platform"), all I get is a 500 error when I call the service. I'm guessing that I'm doing something fundamentally wrong, but all the docs suggest these are the right variable names to use.
You can't access json.platform but at that point json variable is json type. Are you sure that you can add a property to a json type variable if your json object lacks of that property? I mean: What if you first parse the json variable of json type to a normal object, then add new property, and finally stringify to json type again for body assigning purposes?
var json = JSON.parse(apim.getvariable('message.body')); //convert to normal object
json.platform = 'Powered by IBM API Connect'; //add new property
apim.setvariable('message.body', JSON.stringify(json)); //convert to json again before setting as body value
You need to get the context in some determined format, and in this function do your logic. For example if your message is in json you need to do:
apim.readInputAsJSON(function (error, json) {
if (error)
{
// handle error
apim.error('MyError', 500, 'Internal Error', 'Some error message');
}
else
{
//APIC: get the payload
var json = apim.getvariable('message.body');
//console.error("json %s", JSON.stringify(json));
if(json){
//same: code to inject new attribute
json.platform = 'Powered by IBM API Connect';
//APIC: set the payload
//message.body = json;
apim.setvariable('message.body', json);
}
}
});
Reference:
IBM Reference
You have the message.body empty, put a invoke/proxy policy before your gateway/javascript policy for example.

How to pass query string data or any value from url to controller function in AngularJS?

Suppose I have few links in page and each link has date like:
**https://mysite/blogs/01/01/2017
https://mysite/blogs/02/01/2017
https://mysite/blogs/03/01/2017
https://mysite/blogs/04/01/2017**
How can I capture date and fetch data date wise when doing Angular routing ?
I am new so like to know how people pass query string data or any value from url to controller function with example code.
**https://mysite/blogs?custid=101&orderid=200
https://mysite/blogs/{customerid}/orders
https://mysite/blogs/{customerid}/{orderid}**
Please post a small sample code having controller, view and routing code if possible.
I am very eager to see how to handle query string or rest based URL kind with Angular routing which will pass data to controller and controller fetch data accordingly.
$routeProvider.when('/blogs/:day/:month/:year', {
templateUrl: 'blog.html',
controller: 'BlogCtrl'
});
Then in your controller, inject $routeParams to get the params:
function BlogCtrl($scope, $routeParams) {
$scope.day = $routeParams.day;
$scope.month = $routeParams.month;
$scope.year = $routeParams.year;
}
Demo JSFiddle
You could use $location object. Here's a link to the official documentation
And here's a sample of code using it :
if ($location.hash() !== "") {
$scope.date = $location.hash();
$scope.loadData();
} else $scope.initWithDefaultValues();
But your url list should look like this :
**https://mysite/blogs#01/01/2017
https://mysite/blogs#02/01/2017
https://mysite/blogs#03/01/2017
https://mysite/blogs#04/01/2017**
Once you did this, you can also set your browser url this way :
$location.hash( myUrlList[foo].split("#")[1] );
Where myUrlList contains your url list as shown upper.
In order this solution to work, you'll have to declare $http, $location, and perhaps also $anchorScroll depending of what you're doing with your date.
This means that in all other cases that those mentionned in when clauses, the route is redirected to '/'. This solution shows how to use a different controller and route depending on the original url.

How to parse node js response of mongodb data in angular?

I've an http server in node [not express]. On button click I've a get method, which then pulls documents from mongodb (using mongoose) and displays it on angular page.
on button click:
$http.get('/get').success(function(response){
console.log(response);
//logic to store JSON response of database and perform repeat to display each document returned on UI
});
In Node code where server is created using http.createServer instead of express:
if(req.url==="/get"){
res.writeHead(200,{'content-type':'text/plain'});
modelName.find({}, 'property1 prop2 prop3', function(err,docs){
res.write('response...: '+docs);
});
}
Here is my issue:
I'm able to send response from node js to angular js but how to parse it? If I don't add 'response...:' before docs then I get an error msg 'first argument should be a string or buffer'. On angular I get response like:->
response...:{_id:....1, prop1: 'a',prop2: 'b',prop3: 'c'},
{_id:....2, prop1: 'ab',prop2: 'bc',prop3: 'cd'}
I want to display documents as a tabular format
I don't know your exact setup, but I think you should transfer application/json instead of text/plain.
You cannot simply concatenate a string to docs, you need to return either only just docs (to transfer as an array) or write res.write({'response':docs}) (to transfer as an object).
Consider moving from $http to a resource service. In your resource service, you need to set isArray to false if you want to transfer as an object or to true if you transfer as an array: https://docs.angularjs.org/api/ngResource/service/$resource

Reddit Api Error trying to get reddit self text via snoocore node.js

I'm tryng to get the self.text on a post and using this route:
reddit('/r/Denmark/comments/2jc5yk/how_to_live_in_denmark.json').listing({
context: 1,
limit: 10,
sort: 'hot',
})
.then(function(result) {
console.log(result);
});
I have also tried using .get(), without .json and without /how_to_live_in_denmark but still the same error.
When I input the route in my browser, I get the desired JSON.
The error i get:
Uncaught Error: Invalid path provided! This endpoint does not exist. Make sure that your call matches the routes that are defined in Reddit's API documentation
What am i doing wrong?
Update: 2015-02-09
Snoocore now accepts URLS's with embedded values and does not require placeholders if you do not wish to use them.
I'm the creator of this API wrapper. I'll have to monitor StackOverflow a little bit more to catch these quicker. Feel free to open new issues on GitHub as well when you get stuck on something for a quicker response!
It looks like you are trying to call this endpoint:
GET /r/[subreddit]/comments/article
Basically anything that is in brackets is optional in Snoocore, and anything in italics is an URL parameter that you will need to define placeholders for in the call (using $parameter). More information on this can be read in the documentation (feel free to ask questions or improve upon the documentation if it isn't clear!)
So in your case, you will want to do this:
reddit('/r/$subreddit/comments/$article').get({
$subreddit: 'Denmark',
$article: '2jc5yk',
context: 1,
limit: 10,
sort: 'hot'
}).done(function(result) {
console.log(result);
});
Note that instead of defining the url parameters in the call, the are now referenced by $subreddit and $article respectivly.
Note that comments are not a listing, and therefore can't use the listings interface as you tried to do in your question.

AngularJS POSTs empty requests?

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

Categories

Resources