Angular JS: Promise returns resource - javascript

REPOSITORY METHOD
public int CalculateSoundVolume(string roomName, int currentUser)
{
{
//Business Logic
return finalApplauseVolume; //**say returning 75**
}
catch (Exception ex)
{
_logger.LogException(ex);
throw;
}
}
WEB API CONTROLLER
public IHttpActionResult CalculateSoundVolume()
{
try
{
//Some Logic
var result = _applauseRepository.CalculateSoundVolume(huddleName, currentUser);
return Ok(result); // **it returns 75 here in result**
}
catch (Exception ex)
{
_logger.LogException(ex);
throw;
}
}
CLIENT SIDE CONTROLLER (ANGULAR JS)
public calculateSoundVolume()
{
var promise = this.applauseService.calculateSoundVolume();
promise.then((res) => {
this.$log.debug("Sound Volume : ", res);
// Getting Resource [0] : '7' and [1] : '5'
});
}
SERVICE
calculateSoundVolume()
{
return this.soundVolume.get().$promise;
}
Now here the scenario is i am returning an integer value from my Repository method. (say 75). I the WEB API controller the value is recieved as 75 in result.
But the issue is in "res" in my client side controller i am recieving a Resource as [0]:'7' and [1]: '5' i.e the actual and expected value is not recieved. Please suggest any solution

This same issue was happening to me. Turns out the $promise, instead of returning the int, returns an object that breaks the digits of the integer into different indexes in an array along with some other information the promise uses. I was able to resolve the issue by wrapping the integer with a JObject and passing that from the Web API instead of the integer.
So your Web API would look like this:
public JContainer CalculateSoundVolume()
{
try
{
//Some Logic
var result = new JObject(new JProperty("soundVolume", _applauseRepository.CalculateSoundVolume(huddleName, currentUser)));
return result;
}
catch (Exception ex)
{
_logger.LogException(ex);
throw;
}
}
and your client side controller would change to this:
public calculateSoundVolume()
{
var promise = this.applauseService.calculateSoundVolume();
promise.then((res) => {
this.$log.debug("Sound Volume : ", res.soundVolume);
});
Hope that helps
-- Edit --
I should clarify that I am using the Newtonsoft library for JSON in the above code. I found another stackOverflow question which relates Here. In conclusion Chandermani is correct that you should try sending a valid JSON object back from the server instead.

Related

Sending Post with JSON.stringify(obj) in body doesn't result in a string on API recieving side

So I'm a bit stuck on this scenario.
I have a frontend sending the following request through Axios to my API:
const objectInBody = {
Id,
Input
};
const result: any = await axios.Post(`Order/Reservation`, JSON.stringify(objectInBody));
return result.data;
And I have a RESTful .NET Core API running that recieves these requests.
Relevant routing logic:
[HttpPost("[action]")]
public async Task<IActionResult> Reservation([FromBody] string jsonObj)
{
Reservation reservation = JsonConvert.DeserializeObject<Reservation>(jsonObj);
try
{
var result = await orderManager.Reserve(reservation);
return Ok(result);
}
catch (Exception e)
{
return BadRequest(e.Message);
}
}
The problem here is, my API blocks the request, because my API doesn't recognize the 'JSON.stringify(objectInBody)' as a string and will not run through the code.
When I pass other strings, the API accepts it without any problem and continues the logic. Which is weird to me because I thought the JSON.stringify results in a string type?
On console.log(JSON.stringify(objectInBody)); I get {Id:1, Input:1} without quotation marks.
But when I console.log(typeof(JSON.stringify(objectInBody))); it does say 'string' in my console.
I can also adjust the "expected" type in my API to JsonObject or something else, but this is a bad 'fix', since it seems to me Json.Stringify has to return a string and pass it without problems, like I said, not a JsonObject ofcourse.
The reason that your current code is not working, is because Axios don't send Content-Type: application/json automatically for string payloads. Hence, to make your current solution working, you'll have to do like this (please follow my recommendation at the end of this answer instead):
const result: any = await axios.post("Order/Reservation", JSON.stringify(objectInBody), {headers: {"Content-Type": "application/json"}});
Recommended solution
You should change your controller method like this:
[HttpPost("[action]")]
public async Task<IActionResult> Reservation([FromBody] Reservation reservation)
{
try
{
var result = await orderManager.Reserve(reservation);
return Ok(result);
}
catch (Exception e)
{
return BadRequest(e.Message);
}
}
Then change your Axios call like this:
const result: any = await axios.post(`Order/Reservation`, objectInBody);
Assuming that Reservation class is like this
public class Reservation
{
public string Id {get; set;}
public string Input {get; set;}
}
Try this code
objectInBody = {
Id:"id",
Input: "input"
};
const result: any = await axios.Post('/Order/Reservation',
{ jsonObj:JSON.stringify(objectInBody)});

Firestore how stop Transaction?

In transaction I only want to write data if data not present
DocumentReference callConnectionRef1 = firestore.collection("connectedCalls").document(callChannelModel.getUid());
firestore.runTransaction(new Transaction.Function < Void > () {
#Override
public Void apply(Transaction transaction) throws FirebaseFirestoreException {
DocumentSnapshot snapshot = transaction.get(callConnectionRef1);
Log.d(TAG, callChannelModel.getUid());
if (!snapshot.exists()) {
//my code
transaction.set(callConnectionRef1, model);
} else {
//do nothing
}
return null;
});
You can see in my Document reference is uid based and in my log I am printing uid
So where uid's data not exist my Log prints only once and I call transaction.set() elsewhere it keep showing Log of uid where data exists already it looks like my transaction keep running if I don't call transaction.set()
How can I stop it.
It happened to me too on Android. The transaction performs 5 attempts to apply itself, and only then the onFailure() function is called (even if you throw an exception in the apply() function).
But looks like this is the expected behavior:
See here: https://googleapis.dev/python/firestore/latest/transaction.html
Notice MAX_ATTEMPTS defaults to 5.
In this github issue https://github.com/firebase/firebase-js-sdk/issues/520 there's a request to add a "number of retries" option.
There is an example given in the documentation, just throw an exception and it will exit the transaction and stop executing.
db.runTransaction(new Transaction.Function<Double>() {
#Override
public Double apply(Transaction transaction) throws FirebaseFirestoreException {
DocumentSnapshot snapshot = transaction.get(sfDocRef);
double newPopulation = snapshot.getDouble("population") + 1;
if (newPopulation <= 1000000) {
transaction.update(sfDocRef, "population", newPopulation);
return newPopulation;
} else {
throw new FirebaseFirestoreException("Population too high",
FirebaseFirestoreException.Code.ABORTED);
}
}
}).addOnSuccessListener(new OnSuccessListener<Double>() {
#Override
public void onSuccess(Double result) {
Log.d(TAG, "Transaction success: " + result);
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Transaction failure.", e);
}
});
DocSnippets.java

Customize loopback model

How do i customize a PersistedModel in loopback ? Let's say i have two models Post and Comment. A Post hasMany Comment but it can have at most 3 comments. How can i implement that without using hooks? Also i need to do it inside a transaction.
I'm coming from java and this is how i would do that:
class Post {
void addComment(Comment c) {
if(this.comments.size() < 3)
this.comments.add(c)
else
throw new DomainException("Comment count exceeded")
}
}
then i would write a service ...
class PostService {
#Transactional
public void addCommentToPost(postId, Comment comment) {
post = this.postRepository.findById(postId);
post.addComment(comment)
this.postRepository.save(post);
}
}
I know i could write something like:
module.exports = function(app) {
app.datasources.myds.transaction(async (models) => {
post = await models.Post.findById(postId)
post.comments.create(commentData); ???? how do i restrict comments array size ?
})
}
i want to be able to use it like this:
// create post
POST /post --> HTTP 201
// add comments
POST /post/id/comments --> HTTP 201
POST /post/id/comments --> HTTP 201
POST /post/id/comments --> HTTP 201
// should fail
POST /post/id/comments --> HTTP 4XX ERROR
What you are asking here is actually one of the good use cases of using operation hooks, beforesave() in particatular. See more about it here here
https://loopback.io/doc/en/lb3/Operation-hooks.html#before-save
However, I'm not so sure about the transaction part.
For that, I'd suggest using a remote method, it gives you complete freedom to use the transaction APIs of loopback.
One thing to consider here is that you'll have to make sure that all comments are created through your method only and not through default loopback methods.
You can then do something like this
// in post-comment.js model file
module.exports = function(Postcomment){
Postcomment.addComments = function(data, callback) {
// assuming data is an object which gives you the postId and commentsArray
const { comments, postId } = data;
Postcomment.count({ where: { postId } }, (err1, count) => {
if (count + commentsArray.length <= 10) {
// initiate transaction api and make a create call to db and callback
} else {
// return an error message in callback
}
}
}
}
You can use validateLengthOf() method available for each model as part of the validatable class.
For more details refer to Loopback Validation
i think i have found a solution.
whenever you want to override methods created by model relations, write a boot script like this:
module.exports = function(app) {
const old = app.models.Post.prototype.__create__comments;
Post.prototype.__create__orders = function() {
// **custom code**
old.apply(this, arguments);
};
};
i think this is the best choice.

can't retrieve data from async call

I am using ngx-translate service for translations in my angular app. I would like to create method that would accept path to string which needs to be returned. My method looks like this:
public translateString(parameter: string): string {
let message = "";
this.translate.get(parameter).subscribe((response) => {
message = response;
});
return message;
}
But it always returns empty string, I think the problem is the subscribe call so return message gets executed before message = response. Any solutions?
The data is not synchronously available. You'll need to return the observable, and then the caller can subscribe to do what they need to do once the message is available.
public translateString(parameter: string): Observable<String> {
return this.translate.get(parameter);
}
// and then used like this:
SomeService.translateString('hello world')
.subscribe(message => {
console.log(message);
})
use instant
It not require any observables.
this.message = this.translate.instant('Language')
You need to return your message inside subscribe.Like this:
public translateString(parameter: string): string {
let message = "";
this.translate.get(parameter).subscribe((response) => {
message = response;
return message;
});
}

Parse cloud code request.object.get(key) return always undefined

i'm trying to make a simple check before saving an object on Parse.
I'm using the "beforeSave" method to check if object has necessary fields setup correctly before saving.
The problem is that when i try to get a field of my object it return always undefined even if it is setup correcly in log!
Input: {"original":null,"update":{"ACL":{"abcdefghi":{"read":true,"write":true}},"isDeleted":false,"lastEdit":0,"name":"testobject","uuid":"109d0b30-1ad5-408b-ba49-2ce024935476"}}
and cloud code:
Parse.Cloud.beforeSave("MyObject", function (request, response) {
// return always an error with uuid printed
response.error("Object uuid: " + request.object.get("uuid"));
}
This is a sample code, not my real code but as you can see the object passed to this function has "uuid" field inside but request.object.get("uuid") return always "undefined":
Console log:
Result: Object uuid: undefined
Official documentation say to access object fields in this way, so is this a Parse bug or i'm doing some mistakes?
EDIT 1:
As suggested i tryied to log the object in this way:
console.log("Object: " + JSON.stringify(request.object));
console.log("Request: " + JSON.stringify(request));
The result is:
Object: {}
Request: {"object":{}, <some other fields..>}
Any idea?
EDIT 2:
I reproduced correcly the error and it seems to be a bug with ACL;
First i created a new object extending ParseObject (i'm working on Android):
#ParseClassName("Person")
public class ParsePerson extends ParseObject {
public void setName(String name) {
put("name", name);
}
public void setAge(int age) {
put("age", age);
}
public String getName() {
return getString("name");
}
public int getAge() {
return getInt("age");
}
}
And than my background thread it will create and save a test object in this way:
ParsePerson parsePerson = new ParsePerson();
parsePerson.setName("Tom");
parsePerson.setAge(45);
try {
parsePerson.save();
} catch (ParseException e) {
Debug.e("Error code: "+ e.getCode(), e);
}
Than i uploaded this cloud code that does nothing else than log:
Parse.Cloud.beforeSave("Person", function (request, response) {
// log person object
console.log("Object: " + JSON.stringify(request.object));
// respond always success to save the object
response.success();
});
Parse.Cloud.afterSave("Person", function(request) {
// log person object again
console.log("Object: " + JSON.stringify(request.object));
// respond success
response.success();
});
After running it works and it saves correctly the object in the new table. Logs:
Input: {"original":null,"update":{"age":45,"name":"Tom"}}
Result: Update changed to {"age":45,"name":"Tom"}
Object: {"age":45,"name":"Tom"}
The last thing i tryid to do was to set ACL to this object editing android code in this way:
ParsePerson parsePerson = new ParsePerson();
parsePerson.setName("Tom");
parsePerson.setAge(45);
parsePerson.setACL(new ParseACL(ParseUser.getCurrentUser())); // new line
try {
parsePerson.save();
} catch (ParseException e) {
Debug.e("Error code: "+ e.getCode(), e);
}
And after running everything this is the log:
Input: {"original":null,"update":{"ACL":{"userAcl":{"read":true,"write":true}},"age":45,"name":"Tom"}}
Result: Update changed to {}
Object: {}
So is this enough?
EDIT 3:
The only solution i found (this is more a workaround) is to save the object without ACL from Android code and then set ACL in beforeSave on cloud code:
Parse.Cloud.beforeSave("Person", function (request, response) {
// setup ACL for this object
var user = request.user;
var newACL = new Parse.ACL();
newACL.setPublicReadAccess(false);
newACL.setPublicWriteAccess(false);
newACL.setReadAccess(user.id, true);
newACL.setWriteAccess(user.id, true);
request.object.setACL(newACL);
// log person object again
console.log("Object: " + JSON.stringify(request.object));
}
I had a very similar problem. I was making changes to an existing project and when I uploaded the code I started getting error where no errors had been before.
I finally solved it by going back to jssdk version to 1.4.0 in .parse.project
Maybe it solves your problem also.

Categories