Angular get different values from nodejs API - javascript

If I try to call a get on my nodeJS than it's work but I get different values.
I have to submit my search parameters 1-3 times to get the right output.
My Node server get the right search parameter and output the right API response but if I want to print it to my Angular app then it will use a old parameters. I don't understand the behavior.
Request Path:
angular -> nodeJS -> 3rd partie API -> nodeJS -> angular
Is that path wrong? how can I get the current data for angular?
APP.JS
app.get('/url', (req, res) => {
var name = req.query.searchname;
console.log("Output\n---------------------------")
console.log(req.query.searchname);
doGetRequest(name);
return res.send(data);
})
test.service
test(searchName){
this.http.get<any>('http://localhost:3000/url', {
params: {
searchname: searchName
}}).subscribe(data => this.totalAngularPackages = data)
this.log();
}
log(){
console.log(this.totalAngularPackages);
}

The variable this.totalAngularPackages is assigned asynchronously. Any statements that directly depend on it must be inside the subscription. By the time the console.log is run, the variable this.totalAngularPackages is still undefined or holds the previously assigned values. You could learn more about async requests here.
test(searchName) {
this.http.get<any>('http://localhost:3000/url', {params: {searchname: searchName}})
.subscribe(data => {
this.totalAngularPackages = data;
this.log(); // <-- must be inside the subscription
});
}
log() {
console.log(this.totalAngularPackages);
}

Related

JS functions with different parameters communicating results

I'm not sure if this is possible and can't wrap my head around it. I have a larger project where I want to combine a couple of callbacks in different files into one and simply get the data from the different functions. My issue is that I can't seem to fetch the last part which I'll demonstrate in the code.
File one, importing file three and calling the sendUpdate function with 'note' as param.
const three = require("./three")
const note = "test"
three.sendUpdate(note);
File two,
async function getUser(user) {
return await otherfileFarAway.otherFunctionFarAway(user);
}
module.exports = {
getUser
}
File three, where I want to bundle these two up. I'm importing file two
const two = require("two");
async function sendUpdate(note) {
const total = await two.getUser(user);
console.log(note); // Works
console.log(total); // Undefined, duuh
try {
const url
.concat(total)
.concat("/Notes");
const result = await axios.post(
url,
{
Comment: note
},
);
return result.data;
} catch (error) {
logger.axiosError(error);
return null;
}
}
module.exports = {
sendUpdate
}
How would I actually just call getUser in file two from file three and get the value it is getting in file two? Is that possible? If I call it without parameters I get nothing, if I send it with something I get undefined. If I define it beforehand with for example "let user;" I get nothing.
What am I doing wrong or is it just simply not possible to get the returned value?
I suppose you are using Node? If that is that case you need to use exports to make them available via require. Here's some doc
Modify file two to the following to add some debug messages, so you'll see what's wrong:
async function getUser(user) {
console.log(`====== executing getUser() in filetwo with param: `, user);
const result = await otherfileFarAway.otherFunctionFarAway(user);
console.log(`====== returning `, result);
return result;
}
module.exports = {
getUser
}
Your questions seems to be How would I actually just call getUser in file two from file three and get the value it is getting in file two?.
The answer is that you're already calling that filetwo.getUser(...) properly, because otherwise you'd get a syntax error. It's probably that you're not sending the right parameter to it, so otherFunctionFarAway(...) returns nothing/undefined/null.
Edit
After your comment regarding overriding the user var in filetwo, a solution would be, something along the lines:
create and export another function in filetwo which will export the correct user variable
in sendUpdate(...), before calling the present getUser(note) function, make another call to the above function
call getUser() with the result from point 2.

Angular 6 observables - extract data from .subscribe() function and use it elsewhere

I'm banging my head against the wall with observables. Almost all of the documentation I can find is in the older rxjs syntax.
I have an API call which is an observable. I'm calling it elsewhere and subscribing to it - trying to populate a table with the data from this GET request.
If I simply console.log my getData function, it logs the subscription rather than my data.
I can successfully console.log data within the .subscribe function, but I want to use data outside of .subscribe().
How do I extract data out of the .subscribe() function and use it elsewhere? Or, must all of my logic be contained within the .subscribe() function to use data?
getData2() {
return this.m_dbService.get('api/myApiPath').subscribe(
data => (console.log(data)), //This properly logs my data. How to extract `data` out of here and actually use it?
error => { throw error },
() => console.log("finished")
);
}
workbookInit(args){
var datasource = this.getData2(); // this returns the subscription and doesn't work.
}
just return the HTTP req from getData() and subscribe it inside the workbookInit function.
getData2() {
return this.m_dbService.get('api/myApiPath')
}
workbookInit(args){
this.getData2().subscribe(
data => {
var datasource = data
},
error => { throw error },
() => console.log("finished")
}
What you probably want to do is to populate another Observable with the data so that you can access it elsewhere in your project without the need for calling the API more than once.
To do this, you create what is known as a Subject (in this case a BehaviorSubject) and you can populate that with data when your API call returns a response.
Then, in order to access this data elsewhere, you can create a "get" function to return the Subject (which is itself an Observable) whenever you need the data.
Here is an example:
my-data.service.ts
myData: BehaviorSubject<number> = new BehaviorSubject<number>(0);
callApi() {
this.dbService.get('apiUrl').subscribe(
(data) = > this.myData.next(data) // Assuming data is a 'number'
);
}
getMyData() {
return this.myData.asObservable();
}
Now to use this in a component:
this.myService.getMyData().subscribe(
(data) => { /* Use the value from myData observable freely */ }
);
Or you could rely on the Angular async pipe (which is a very convenient method for dealing with observables in your code).
You should not subscribe to the Observable inside getData2. Return it as is instead, then do the following:
var dataSource;
this.getData2().subscribe(res => dataSource = res);
Please note that the variable dataSource will be set when the request is done (asynchronously), so you can't use it immediately in the same block scope.
If you want to use it immediately, then put your code inside the subscription.
If you have an observable that provides data to populate a table, the best way is not to use subscribe(), but use the observable directly in your html template by using the async pipe. You'll have less to worry about and your code will be much simpler.

How to return a result from Meteor.call method in client?

I'm calling a server method from my client side code via the Meteor.call() function.
But I get an undefined value when I try to pass the callback function's return value to a var within the onCreated function.
Looking at this solution the result is still only available within the scope of the callback:
https://stackoverflow.com/a/31661065/1829251
Also when I read the docs for Meteor-call it explains that the method is async which explains that the return value of the function can't be assigned to a variable:
https://docs.meteor.com/api/methods.html#Meteor-call
Question:
How can you return a result from Meteor.call method in client?
Code snippet of client side code:
import { Template } from 'meteor/templating';
import { Meteor } from 'meteor/meteor';
import { Datasets } from '../../../../api/datasets/datasets.js';
import { Constants } from '../../../../startup/constants.js';
import './rollup-history.html';
import './rollup-history.scss';
Template.rollup_history.onCreated(function() {
this.historyDays = 7;
this.rollupHistoryMECTitles = () => {
let mecObjects = [];
// Query the MEC calendar dates from AppConfiguration collection
let method = Constants.Methods.getAppConfigCollectionFromKeyDateSorted;
mecObjects = Meteor.call(method, Constants.AppConfigKeys.meccalendarInitialValues, this.historyDays, (error, result) => {
if(error){
console.log("Error retrieving MEC Dates" + error);
}
//Logging values here shows the values as expected
console.log("MEC Dates in View" + JSON.stringify(result));
return result;
}
);
//logging value here shows undefined value
console.log("mec objects: " + JSON.stringify(mecObjects));
return mecObjects;
};
});
Template.rollup_history.helpers({
mecHeaderColumns: function() {
return Template.instance().rollupHistoryMECTitles();
},
});
Because the return statement is in the callback and is unblock you can't return a method value like that. you can put it https://github.com/stubailo/meteor-reactive-method which will return the value but it must live inside a helper or reactive environment.
short answer:
define your Meteor.Method inside common code (code available to server and client) then use Meteor.apply with the option { returnStubValue : true }
mecObjects = Meteor.apply(method, [Constants.AppConfigKeys.meccalendarInitialValues, this.historyDays], { returnStubValue: true }, (error, result) => {
if(error){
console.log("Error retrieving MEC Dates" + error);
}
//Logging values here shows the values as expected
console.log("MEC Dates in View" + JSON.stringify(result));
return result;
}
);
console.log(mecObjects) //prints the client-side result of the meteor method
longer answer:
Meteor allows for Optimistic-UI which is simulating a server method on the browser. To enable this, define your Meteor.Method in common code (server + client space). This is useful because the user can see the UI updates faster since we don't need to make a server-round trip.
Notice that in the picture above, the method call runs first on the client and later on the server. { returnStubValue: true } allows the caller to receive the method's return value from the client run
When writing a Meteor method, you can use this.isSimulation to specify what logic runs exclusively on client or server. Any code outside of this check runs in both.
Note that in the picture above that the server only runs console.log("hi i'm server") while only the browser runs console.log("hi i'm client"). Both run the code outside of the isSimulation check.
A few concerns:
What if the server return value is different from the client return value?
result != mecObjects so you will need to handle that situation properly.
What if the client run fails? Does the server still run?
Yes, the server still runs. However you can prevent server runs on client
failures by adding another option, throwStubExceptions: true. This option will
throw client exceptions which you can capture in a try catch.
What if the client and server mongo updates are different?
The server mongo changes override the client mongo changes.
see more at
https://guide.meteor.com/methods.html and https://forums.meteor.com/t/how-to-return-value-on-meteor-call-in-client/1277/2
The value of your mecObjects will always be undefined, because Meteor.call function doesn't return anything. Server's method call response (or error) will be passed to callback only, like in your code, actually: those error and result variables.

How to retrieve data from mongoose sequentially?

get: function (code) {
console.log('Retrieving model for code : ', code);
let database = UTILS.getDatabase('databaseName');
return database.models.modelName.find({})
.then(function (users) {
console.log(' ----------- ', users);
return users;
})
.catch(function (error) {
return '{success: "false", msg: "Error found : ' + error + '"}';
});
}
This code is running without any errors, but the function that calls "get" couldn't find any record, while callback function prints around 8-9 records in console. I know this is callback functionality, but I need this to be happen sequentially.
I also tried to use yield return yield database.models.modelName.find({}) with * function, but getting {}, an empty object.
Please suggest a way to avoid callback and get data from mongodb.
Thanks Julien, but I can't use callback, because the function which is calling "get" has logic to process object return from mongoose.
Hi Ravi, here is complete flow of this process stack. Route -> Controller -> Facade -> Service -> Dao (the code I posted is belongs to Dao layer get function)
This looks typical typed language solution, but I need this to be in this way.
a Service layer function could collect data from multiple model and could be processed collectively, so callback process doesn't fulfill my requirement here.
I am completely stuck, Thanks for help :)
Router :
app.route('/nodics/users')
.get(CONTROLLER.UserController.get)
.post(CONTROLLER.UserController.set);
Controller:
get: function (request, response, error) {
let users = FACADE.UserFacade.get();
response.json(users);
}
Facade :
get: function (code) {
console.log('inside Facade call....', code);
return SERVICE.UserService.get(code);
}
Service :
get: function (code) {
console.log('inside Service call....', code);
return DAO.UserDao.get(code);
}
Dao method is already there at top. This is a sample layered implementation. but I just want to to be implemented in this way only. so that I can call, DAO layer method anytime and from anywhere in the Service layer.
Use Case:
1. I want to add one item into cart, so I pass, PID, SKUID and quantity to the router, which simply pass controls to controller.
2. Controller pass it to facade and Service.
3. In service layer
1. Call another service to check if quantity is valid
2. Call DAO to load product item
3. Call another DAO to load Inventory (or use from first call)
4. Call another DAO to load price item, based on local and currency, or other parameters.
5. Finally load ORDER and add this item into it and save it
6. Return order item to facade layer
4. In Facade, apply filter to return only fields required to expose as service.
So If I want to implement this use case, getting data by callback from mongoose will not help.
So please suggest me the way to get data directly from mongoose without using callback.
You need to pass a callback to your function and call it from your promises:
get: function (code, cb) {
console.log('Retrieving model for code : ', code);
let database = UTILS.getDatabase('databaseName');
return database.models.modelName.find({})
.then(function (users) {
console.log(' ----------- ', users);
cb(users);
})
.catch(function (error) {
cb({success: "false", msg: "Error found : ' + error + '"});
});
}

API using Hapi & Async - How to empty array / execute something right after "reply" or at each new "get"?

I'm building a small API that fetches data and perform tasks on it (using async), stores some of this data in an array using push, and then shows it to a client with Hapi's reply().
I'm looking to empty my array (for example using arrayname.length = 0) right after the server has sent an answer to the client.
Current code follows this logic:
let data = []
server.route({
method: 'GET',
path: '/api/{data}',
handler: function (request, reply) {
async.parallel([
function(callback) {
// fetch some data, work with it and then add it to our array using push
data.push ({ // example data
bla:'blabla',
number:'10'
});
callback();
},
function(callback) { // another time (...)
data.push ({
bla:'blabla',
number:'2'
});
callback();
}
],
function(err) { // This is the final callback, sort data and send it using reply
data.sort(function (a, b) {
return a.number - b.number
})
reply(data)
console.log(request.params.data)
})
}
});
server.start((err) => {
if (err) {
throw err;
}
console.log(`Server running at: ${server.info.uri}`);
});
With the current code if I refresh my page, data gets added to the already existing data array.
I tried for several hours and find no way to empty this array right after reply(data) has been called.
Is there any way to do that, or would I have to nest my parallel async functions with an async serie and perform the emptying that way? (Haven's been able to succeed either + sounds overkill).
Is there a way to simply execute something once "reply" has been called or when there is a new "get" so that each client can have the only the data generated by it's request and not also the data that was in the array before?
Thanks!
I'm in agreement with all of the answers suggesting to put the array within the handler. With the array situated out side of the request handler, all request coming through will be writing to the same array. Even if you clear this array at the end of your handler logic, it is not guaranteed to be empty for the next request context since you can have many request context in play.
Following #piotrbienias's advice I created the array inside handler rather than at the beginning of my file and it's cleared each time I do a new request on my API, so I don't need to empty it once the reply is sent.
Thanks, #piotrbienias!

Categories