Get a javascript object's methods with http get request? - javascript

I have an object constructor in my server file that constructs an object that includes some functions. When I send the object with Express in my server.js file and retrieve it with an axios get request in my app.js file, the object's functions are missing. Why is this? How can I send/get the functions with the object?
I'm using React (I don't think that matters though). The functions allow me to update the object's data. The object is supposed to act as a folder for other sites.
Server.js
const sites = []; //array that holds objects
//this function generates a random ID for the object
const makeID = function () {
return '_' + Math.random().toString(36).substr(2, 9);
};
//Here is my object (site constructor)
const makeSite = (customerInfo={}, parent=undefined, isMain=false, isFile=false, subsites=[]) => {
const site = {
customerInfo,
isMain,
subsites,
isFile,
id: makeID(),
get title() {
if (!this.isMain) {
return `${parent.title}/${this.customerInfo.name}`;
} else {
return this.customerInfo.name;
}
},
addSubsites(subsite_arr) {
this.subsites += subsite_arr;
}
};
return site;
}
//Here is a function that allows me to make a default object and add it to the array of sites
publishSite = (info) => {
const newSite = makeSite(info, undefined, true, false); //calling constructor
newSite.addSubsites([ //default subsites
makeSite({name: 'Scope'}, newSite),
makeSite({name: 'Notes'}, newSite),
makeSite({name: 'Material'}, newSite),
makeSite({name: 'Changes'}, newSite),
])
sites.unshift(newSite);
}
publishSite({name: "RED"}); //adds object to sites array
app.listen(port, () => console.log(`Listening on port ${port}`));
// create a GET route
app.get('/sites', (req, res) => {
res.send(sites); //sends sites array (see top of code)
});
App.js
//function that gets sites array and logs it to console/updates state
async refreshSites() {
const {data} = await Axios.get('/sites');
console.log(data);
this.setState({sites: data})
}
When I run the app, this is logged to the console
[{…}]
0:
customerInfo: {name: "RED"}
id: "_pppxh5zy6"
isFile: false
isMain: true
subsites: (4) [{…}, {…}, {…}, {…}]
title: "RED"
__proto__: Object
length: 1
It has all the info except for the methods, and calling the methods throws an error. It's also worth noting that the 'title' property of the object never changes even when I change the objects customerInfo.name directly. How can I send the object's methods and call them in app.js (such as addSubsites)?

You can't send functions through the http protocol. If you wish to use the same constructor and methods, my tip is, move all this code to a file without any environment (nodejs, browser) references, and use the same file in both places.

Related

Vue prefetch data from separate backend

I have some queries from an API-Server that returns a json object that will be static over a user session, but not static forever.
It's a one-pager with Vue router.
How can I achieve that I:
can access this.myGlobals (or similar eg window.myGlobals) in all components, where my prefetched json-data from API-Server is stored.
My approach that is already working is to embed help.js via a mixin.
Oddly enough, I get hundreds of calls to this query. At first I thought that it only happened in the frontend and is chached, but the requests are actually sent hundreds of times to the server. I think it is a mistake of my thinking, or a systematic mistake.
i think the problem is, that the helper.js is not static living on the vue instance
main.js:
import helpers from './helpers'
Vue.mixin(helpers)
helpers.js:
export default {
data: function () {
return {
globals: {},
}
}, methods: {
//some global helper funktions
},
}, mounted() {
let url1 = window.datahost + "/myDataToStore"
this.$http.get(url1).then(response => {
console.log("call")
this.globals.myData = response.data
});
}
}
log in console:
call
SomeOtherStuff
(31) call
SomeOtherStuff
(2) call
....
log on server:
call
call
call (pew pew)
My next idea would be to learn vuex, but since its a easy problem, im not sure if i really need that bomb ?
You can use plugin to achieve this.
// my-plugin.js
export default {
install (Vue, options) {
// start fetching data right after install
let url1 = window.datahost + "/myDataToStore"
let myData
Vue.$http.get(url1).then(response => {
console.log("call")
myData = response.data
})
// inject via global mixin
Vue.mixin({
computed: {
myData () {
return myData
}
}
})
// or inject via instance property
Vue.prototype.$myData = myData
// or if you want to wait until myData is available
Vue.prototype.$myData = Vue.$http.get(url1)
.then(response => {
console.log("call")
myData = response.data
})
}
}
and use it:
Vue.use(VueResource)
Vue.use(myPlugin)

How to perform two firebase database operation on different nodes in single request/function?

I am a react-native developer and new to firebase. I am performing firebase realtime database operation, have a look at code below;
firebase.database().ref('events/wedding/items').push(object).then((data) => {
//success callback
dispatch(addPendingInvoice({ ...invoice, id: data.key }))
Alert.alert('Successfully added to Invoices', 'Please go to invoice section to clear first and continue.', [{ text: 'Ok' }])
}).catch((error) => {
//error callback
Alert.alert("Can't book package.", 'Please check your internet connection!', [{ text: 'OK', style: 'destructive' }])
})
Now, I wish to push another object to another node events/wedding/packages right after this firebase database function above. I can use another function inside then callback in above firebase functions. This is not a professional way to do this.
Is there any way to do this?
You can use the update() method to "simultaneously write to specific children of a node without overwriting other child nodes". Note that "simultaneous updates made this way are atomic: either all updates succeed or all updates fails", see the doc.
So in your case you would do along the following lines:
var newNodeKey = firebase.database().ref().child('events/wedding/items').push().key;
var updates = {};
updates['events/wedding/items/' + newNodeKey] = { foo: "bar" };
updates['events/wedding/packages/' + newNodeKey] = { bar: "foo" };
firebase.database().ref().update(updates)
.then(() => {
// The two writes are completed, do whatever you need
// e.g. dispatch(...);
});
All Firebase operations return a promise so you can use Promise.all() to run them all simultaneously.
Promise.all([
firebase.database().ref(reference).set({}),
firebase.database().ref(reference2).set({})
]).then(() => {
console.log("Operations Successful")
}).catch((e) => console.log(e))
You can also push all your operations to an array and then pass that array in Promise.all()

Building Nuxt sitemap from multiple data sources

I'm working with Nuxt in SSR mode and want to build out a dynamic sitemap for multiple routes/ data sets.
The issue I'm facing now is that the async/ await function only allows 'data' as the variable. The same function with 'post' as the variable leads to a "map function does not exist"
This is what's in my Nuxt.config.js file
sitemap: {
hostname: "https://example.com",
routes: async () => {
let { data } = await axios.get('https://api.example.com/api/v1/locations');
data = data.data.map((loc) => `/locations/${loc.slug}`);
console.log(data);
let { posts } = await axios.get('https://cms.example.com/wp-json/wp/v2/posts');
posts = posts.map((post) => `/posts/${post.slug}`);
console.log(posts);
data.concat(posts);
return data
},
path: '/sitemap.xml'
}
The resulting output I'm looking for should be formatted like this:
[
'/locations/location-one',
'/locations/location-two',
'/locations/location-three',
'/posts/post-one',
'/posts/post-two',
'/posts/post-three',
]
The error I'm getting:
Cannot read property 'map' of undefined
and it's occuring on this line:
posts = posts.map((post) => `/posts/${post.slug}`)
so it appears to me that it's not accepting 'posts' as a valid variable for its own await function.
That call works fine when the first call is commented out and 'data' is used instead of 'posts'
your destructured response is wrong:
replace:
let { posts } = ...
by:
let { data: posts } = ...
Because Axios always returns a "data" attribute, so you just have to rename it as "posts".
Your array concatenation must be like that:
data.concat(posts);
(see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat)
The push() method is only to push one item, but not an array of item.
(see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push)

Array of JSON object is not empty but cannot iterate with foreach, show zero length [duplicate]

This question already has an answer here:
How to get data from firestore DB in outside of onSnapshot
(1 answer)
Closed 3 years ago.
I read a collection about book checkout from firestore in create().
The data is store in checkout array that declared in data().
export default {
name: "checkout-history",
data() {
return {
checkout: []
]
};
},
created() {
db.collection("checkout")
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = {
id: doc.id, // firebase document id
book_did: doc.data().book_did,
borrowed_date: doc.data().borrowed_date,
copies_did: doc.data().copies_did,
due_date: doc.data().due_date
};
this.checkout.push(data); // push to array
});
});
console.log(this.checkout) // show data, as in the image below
console.log(this.checkout.length) // get 0
console.log(Object.keys(this.checkout).length) // get 0
}
......
When I run console.log(this.checkout);, console show this:
However, I cannot iterate it, the console show this.checkout.length is 0
I also tried to use Object.keys but no luck.
Object.keys(this.checkout).forEach(key => {
const keys = this.checkout[key];
console.log(keys);
});
I really don't know what to do anymore.
I read many answers online and tried most of them, but none of them work.
I guess you are executing your code before the completion of the request.
If you hover over the little blue i icon, it says:
Value below was evaluated just now.
Data is loaded from Firestore (and from most modern web APIs) asynchronously. This means that the rest of your code continues to execute after you start the query, and then when the data comes back from the database, your then() callback is called. This in turn means that all code that needs access to the data from the database, must be inside the then() callback.
db.collection("checkout")
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
const data = {
id: doc.id, // firebase document id
book_did: doc.data().book_did,
borrowed_date: doc.data().borrowed_date,
copies_did: doc.data().copies_did,
due_date: doc.data().due_date
};
this.checkout.push(data); // push to array
console.log(this.checkout) // show data, as in the image below
console.log(this.checkout.length) // get 0
console.log(Object.keys(this.checkout).length) // get 0
});
});
}
......
Also see:
How to get data from firestore DB in outside of onSnapshot
Why are Firebase APIs asynchronous?

Can't extract data from $resource (consuming rest webservice)

I'm trying to consume a REST webservice, responding with a JSON String containing a fairly "complex" schema.
I created a model that contains every fields sent by the webservice.
Here are the relevant codes that should be a problem :
public getUser(user_id: number): PlanDeCharge.Modeles.User {
var toto;
this.UserRest.get({ user_id: user_id }, function(){}, function(err){
this.$window.location.href = "http://localhost:8080/myapp_webapp/login.do";
}).$promise.then(function(data){
toto = data;
});
return toto;
}
-
this.userConnecte = this.gestionUserService.getUser(759);
-
export function userRest($resource: ng.resource.IResourceService, $cookies: ng.cookies.ICookiesService): PlanDeCharge.Modeles.IUserResource {
this.key = $cookies.get("encodedKey");
var urlService: string = "http://localhost:8080/teambox_webapp/resource-rest/V1_1/users/:user_id";
return <PlanDeCharge.Modeles.IUserResource> $resource(urlService, {user_id: "#user_id"}, {
get:{
headers:{"key" : this.key}
}
});
}
app.factory("UserRest", ["$resource", "$cookies", userRest]);
I did a lot of modifications, trying to fix the call without success... The request actually get a response containing the JSON string, but I can't put it inside an object to be use (like user['id'] = 2)
Thanks in advance
I deleted the last post and made this new one, the first one wasn't clear enough and people were confused
When working with promises you should let Angular handle the resolvement.
Am I right, if you are actually using AngularJS 1 and not ng2 as the question is tagged? The syntax is ng1 anyways.
Some notes on the getUser method. Return the reference created by $resource instead of creating one your self. Further more, use the fat-arrow syntax on the callbacks to bind this to the proper context. See this article for more on this.
To remove even more code use TypeScripts object initialization and init the user id object with just { user_id }. This creates a JavaScript object with a property user_id with the value of user_id.
public getUser(user_id: number): SomeModel {
return this.UserRest
.get({ user_id }, () => { }, () => {
this.$window.location.href = "http://localhost:8080/myapp_webapp/login.do";
});
}
In your component or controller access
this.userConnecte = this.gestionUserService.getUser(759);
Lastly, the factory/service.
Use the fact that $resource is generic and set your variables as constants when not changed.
export function userRest(
$resource: ng.resource.IResourceService,
$cookies: ng.cookies.ICookiesService
): ng.resource.IResourceClass<PlanDeCharge.Modeles.IUserResource> {
this.key = $cookies.get("encodedKey");
const urlService = "http://localhost:8080/teambox_webapp/resource-rest/V1_1/users/:user_id";
return $resource<PlanDeCharge.Modeles.IUserResource>(urlService, { user_id: "#user_id" }, {
get: {
headers: { "key": this.key }
}
});
}
This should fix your problems and make to code more readable. :)

Categories