AngularJS treats POST response as string array instead of just string - javascript

I am making a POST request:
var offers = $resource('/api/offers/:id', {
id: '#id'
}
offers.save({}, { name: $scope.newOfferName }, function (offerId) {
$location.path('/offers/' + offerId);
});
I expect offerId to be a string "key", but instead I get an array [0] "k", [1] "e", [2] "y".
On the backend I use Nancy and I return the response using:
Post["/"] = _ =>
{
return Response.AsText("key");
};
The response Header say Content-Type:text/plain and in Chrome preview (Network tab) I can see "key".
When I return an object as JSON it's working fine, but I don't want to create fake class (having a string field) just to pass a string to the client.
I assume Nancy is fine here. What is happening with Angular?

You don't have to create a class for that. You can use an anonymous type:
Post["/"] = _ =>
{
return Response.AsJson(new { offerId = "key" });
};

angular has a default transform that tries to parse incoming data as json.
https://github.com/angular/angular.js/blob/master/src/ng/http.js#L94
You could remove that transform from the transformers array in $http completely, or replace it with one that checks the content-type before trying to transform the data.

Related

How do I fetch Weather's API 'forecastday' using axios?

I use WeatherAPI's service, which returns the weather forecast given the city name
The URL looks like this https://api.weatherapi.com/v1/forecast.json?key=[API_KEY]&q=tokyo&aqi=no
After trying to paste that URL into my browser and pasting the result into a JSON beautifier, here's the result
Here's the weird part. I tried using axios to fetch the information from my app and printing it out, this is what it gave me
It was unable to fetch forecastday and instead gave me a [Object], which didn't make any sense to me since it worked just fine on my browser
Here's my code (sorry for the spaghetti formatting)
https://pastebin.com/9eJQy5Bf
I tried reinstalling the library, using proxies but the result remained the same.
forecast.forecastday is an object array, to access a property from a particular object, you have to specify the index of the object in the array.
For example if you want the date property of the first object.
const data = {
forecast: {
forecastday: [{
date: "2022-04-03"
}]
}
}
const date = data.forecast.forecastday[0].date; // index [0] = first element
console.log(date);
If you would have multiple days, you could loop over them or use a function like map() to get the specific items.
const data = {
forecast: {
forecastday: [{
date: "2022-04-03",
date_epoch: 123456789
},
{
date: "2022-04-04",
date_epoch: 123456789
}
]
}
}
const dates = data.forecast.forecastday.map(({ date }) => {
return { date }
});
console.log(dates);

How to use JSON response as an array in javascript

Here is my response I get from API request:
[ 'bookShelf3', 'bookShelf4', 'bookShelf5' ]
Here is a part of my code which searches through my mongoDB Databese:
const responseToSearchC = (req, res) => {
console.log(req.body.searchTerm);
db.collection('subtitle')
.find({
series: { $in: ['bookShelf1'] },
$text: { $search: req.body.searchTerm },
})
I just want to make my code dynamic and instead hard coding ['bookShelf1']
set its value by JSON response.
the problem is the response from API is an object (although it is look like an array) and I cannot replace it with my hard codded array ['bookShelf1']
I tried to stringify it but it didn't work cuz its a string again, and not an array like hardcoded one
If the response is really an object like:
{ 0: 'bookShelf3', 1:'bookShelf4', 2: 'bookShelf5'}
you can simply utilize the Object.values() method which returns all of the object's values as an array.
Here's an example:
let ob={ 0: 'bookShelf3', 1:'bookShelf4', 2: 'bookShelf5'};
console.log(Object.values(ob));

How to collect strings, sent from angularJS, in NodeRED array?

I'm trying to collect strings I send from AngularJS to a NodeRED array. The AngularJS code looks like this
this.user =
{
medName1: '',
medTime1: ''
},
{
medName2: '',
medTime2: ''
},
{
medName3: '',
medTime3: ''
};
I'm collecting form data in medName1, medTime1,.. and so on. I'm trying to send this data, over websocket, one by one to NodeRED using the following code
this.register = function() {
$scope.sock.send(this.user.medName1);
$scope.sock.send(this.user.medTime1);
$scope.sock.send(this.user.medName2);
$scope.sock.send(this.user.medTime2);
$scope.sock.send(this.user.medName3);
$scope.sock.send(this.user.medTime3);
}
register() is called when I click on "submit" button.
My question is - How do I store these strings in a nodeRED array?. Because the way I'm sending it, the string always gets stored in array index 0, overwriting the previous string. I also tried
$scope.sock.send(JSON.stringify(this.user));
but it sends the entire thing as a string to nodeRED which then makes it impossible to extract the values assigned to medName1, medTime1, and so on.
Can anyone please suggest a way!.. I'll really appreciate your help.
If you send the json.stingify version, you can then use a JSON node in your Node-RED flow to convert it back to the JavaScript object you want.
First, make your this.user an actual array:
this.user =[
{
medName1: '',
medTime1: ''
},
{
medName2: '',
medTime2: ''
},
{
medName3: '',
medTime3: ''
}];
Then, send the this.user array in a single step just as you mentioned:
this.register = function() {
$scope.sock.send(JSON.stringify(this.user));
}
Then, in NodeRED use this:
var user_array = JSON.parse( the_serialized_array );

AngularJS Not able to pass model data to server model appears as empty string

I'm trying to send some simple data to the server. I take the originally received server data used to create dynamic forms, quickly clean up unnecessary keys using delete formData['not_needed'], and then I wanted to add the model that has been created before posting to the server, but when I check the data objects model key that I'm trying to add it is always an empty string. I can either send one or the other, but can't seem to add one object to another as a key-value pair.
// Abridged version
var formData = $scope.responseData; // original server data to build forms
delete formData['config_data']; // remove unnecessary keys
formData.model = $scope.formModel; // add model key
$http.post('/restful/api', formData).then(function(success) {...}, function(error) {...});
The output of passed data from the server looks like:
{ id: "1", type: "type_of_form", name: "name_of_package", model: "" } // model always empty
Is this an issue using $scope?
UPDATE
Even when I hardcode the outgoing keys:
var packageData = {
"packageid": $scope.formData.id, // makes it to server
"desc": $scope.formData.desc, // also makes it to server
"data": $scope.formModel // is just an empty string
}
But formModel filled from some dumby form data when logged to console and printed out to the screen using a filter { formModel | json } looks like:
formModel = {
"document_date": "1234",
"first_name0": "1",
"first_name1": "2",
"first_name2": "3",
"first_name3": "4"
}
It could be that you're running into the by-now famous "AngularJS cannot form-URL-encode data it POSTs by default" pitfall; if so, you'll need to do this before you try and post:
.config(['$httpProvider', function ($httpProvider) {
// Intercept POST requests, convert to standard form encoding
$httpProvider.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
$httpProvider.defaults.transformRequest.unshift(function (data, headersGetter) {
var key, result = [];
for (key in data) {
if (data.hasOwnProperty(key)) {
result.push(encodeURIComponent(key) + "=" + encodeURIComponent(data[key]));
}
}
return result.join("&");
});
}]);
via How can I post data as form data instead of a request payload?

Return all from type - Freebase MQL

Why does this return a 400 error (Unique query may have at most one result. Got 100):
[{
name:null,
type:'music/artist'
}]
I'd expect it to return the first 100 names from music/artist? How is it a unique query?
I'm trying to build a random query, where I can provide two params - the page and the result from within the page to return - and get one item back
Would be awesome if MQL supported something like return: 'random'
EDIT - adds full Angular factory. The query runs fine if I punch it in to the freebase.com/query engine.
myApp.factory('FB_Random', function ($http) {
return {
fn: function (callback) {
$http.get("https://www.googleapis.com/freebase/v1/mqlread",
{
params: {
query:[{
name: null,
type: '/music/artist'
}]
}
}
).success(function (d, status, headers, config) {
callback(d.result);
}).error(function (d, status, headers, config) {
console.log(d);
});
}
};
});
Looks like there's some undocumented Angular behavior going on here. According to the Angular docs, the params parameter takes a "Map of strings or objects which will be turned to ?key1=value1&key2=value2 after the url."
However, it seems like there's some additional logic that looks for array values in the params map and turns them into repeated parameters; ie. ?query={...}&query={...}. Since your query is (properly) wrapped in array notation, indicating that you're expecting multiple results, Angular interprets it as a list with a single value for the query parameter. It then extracts that query parameter and adds it to the url like so:
https://www.googleapis.com/freebase/v1/mqlread?query={%22name%22:null,%22type%22:%22/music/artist%22}
This is why you get the error about your query incorrectly asking for a single result. Because Angular removed the outer array notation that's needed by MQL.
The simplest way to work around this is to simply wrap your query in an additional array like this:
$http.get("https://www.googleapis.com/freebase/v1/mqlread",
{
params: {
query:[[{
name: null,
type: '/music/artist'
}]]
}
}
)
If you'd like to make the fix more explicit and your code easier to read you can just stringify the MQL query yourself like this:
$http.get("https://www.googleapis.com/freebase/v1/mqlread",
{
params: {
query: JSON.stringify([{
name: null,
type: '/music/artist'
}])
}
}
)

Categories

Resources