Get json data in VueJS - json

onMounted(() => {
productService.value
.getProducts()
.then((data) => (products.value = data));
console.log((products))
});
When I print products with console.log, here what I have.
capture of the console
I see that the data I want are in RawValue but I don't know how to access them.
I tried Object.values(products) or just console.log(products._rawValue) or console.log(products.rawValue) it print undefined.
Do you know what function call ?
Thanks

There are 2 issues
#1 - you're using console.log(products) which shows you the reactive object, what you need instead is console.log(products.value) which will only show the value, which should match the content of data.produtcs
#2 - you might find that 👆 now shows an empty result. The reason that's happening is that you're calling the console log after the async function, but before it finishes, so you're calling it before it has a chance to update. To fix that, you can log as part of the async function
onMounted(() => {
productService.value
.getProducts()
.then((data) => {
products.value = data;
console.log(products.value);
})
});
If you're using the products inside a template, you don't need to worry about what's before or after the async function since it will re-render the component on change.
Also, you probably don't need to define productService as a ref, the class is likely not something that needs to be reactive, so you can just do simple assignment and then skip the .value to call getProducts

with axios what I do is take out the data with response.data you could try
onMounted(() => {
productService.value.getProducts().then((response) => (
products = response.data
));
console.log(products.length);
});

Related

Composable functions in Puppeteers page.Evaluate

I'm relatively new to puppeteer and I'm trying to understand the patterns that can be used to build more complex apis with it. I am building a cli where I am running a WebGL app in puppeteer which i call various functions in, and with my current implementation i have to copy and paste a lot of setup code.
Usually, in every cli command i have to setup pupeteer, setup the app and get access to its api object, and then run an arbitrary command on that api, and get the data back in node.
It looks something like this.
const {page, browser} = await createBrowser() // Here i setup the browser and add some script tags.
let data;
page.exposeFunction('extractData', (data) => {
data = data;
})
await page.evaluate(async (input) => {
// Setup work
const requestEvent = new CustomEvent('requestAppApi', {
api: undefined;
})
window.dispatchEvent(requestEvent);
const api = requestEvent.detail.api;
// Then i call some arbitrary function, that will
always return some data that gets extracted by the exposed function.
const data = api.arbitraryFunction(input);
window.extractData(data)
}, input)
What i would like is to wrap all of the setup code in a function, so that i could call it and just specify what to do with the api object once i have it.
My initial idea was to have a function that will take a callback that has this api object as a parameter.
const { page, browser } = wait createBrowser();
page.exposeFunction(async (input) =>
setupApiObject(((api) =>
api.callSomeFunction(input)
), input)
However, this does not work. I understand that puppeteer requires any communication between the node context and the browser to be serialised as json, and obviously a function cant be. Whats tripping me up is that I'm not actually wanting to call these methods in the node context, just have a way to reuse them. The actual data transfer is already handled by page.exposeFunction.
How would a more experienced puppeteer dev accomplish this?
I'll answer my own question here, since i managed to figure out a way to do it. Basically, you can use page.evaluate to create a function on the window object that can later be reused.
So i did something like
await page.evaluate(() => {
window.useApiObject = function(callback: (api) => void){
// Perform setup code
callback()
}
})
Meaning that later on i could use that method in the browser context and avoid redoing the setup code.
page.evaluate(() => {
window.useApiObject((api) => {
api.someMethod()
})
})

Puppeteer returns undefined for page.evaluate despite being resolved on devtools

I have a simple code in which I expect to find the element that contains certain text as such
await page.goto('https://www.reddit.com/r/koreanvariety/comments/hsdt4j/the_great_escape_season_3_e12_back_to_the/')
await page.waitFor(2000);
const findComment = await page.evaluate(() => {
return Array.from(document.querySelectorAll('a')).find(el => el.textContent === 'sometext' )
})
console.log('findComment', findComment)
And although the code above works on devtools it returns undefined in my windows console.
I believe the page is not fully loaded by the time this request is made however I have not been able to get any results back when resorting to await page.waitFor(2000);.
How do I get data back from page.evaluate?
This is expected behavior
In order to get data from page.evaluate one must return serializable value, i.e. a value that can be stringified with JSON.stringify.
From the documentation:
If the function passed to the page.evaluate returns a non-Serializable value, then page.evaluate resolves to undefined.
Solution
A whole DOM node (that you find in your script) cannot be serialized because it has circular references. You will have to choose which data from the node you want and explicitly return those:
const findComment = await page.evaluate(() => {
return Array.from(document.querySelectorAll('a')).find(el => el.textContent === 'sometext' )?.href
})

console.log is different from json.push

I am using node.js to export a collection that I have in firestore.
Until now the connection and the selection of the documents of the collection work perfectly.
I am trying to save the structure in a json file but the result is not what I expected.
This is the output in the physical file:
enter image description here
On the right of the photo, it will be seen as presented by the console.log and on the right it is displayed as recorded by json.push
I can't get the physical file to have the structure shown in the console.log.
I appreciate all your help.
as you will see the structure here is failing: "USBCALI|AFILIADO|uqcMSoxdwCTQoLzS2J6brNTZ3Dy2",
":",
{.....
should be: USBCALI|AFILIADO|uqcMSoxdwCTQoLzS2J6brNTZ3Dy2 : {.....
this is the code
const jsonfile = require('jsonfile')
function start (db, file, collection) {
const ref = db.collection(collection)
const json = []
console.log(`Getting ${collection}...`)
ref
.get()
.then((snapshot) => {
snapshot.forEach((doc) => {
console.log(doc.id, ':', doc.data())
json.push(doc.id, ':', doc.data())
})
console.log(`Writing ${file}...`)
jsonfile.writeFile(file, json, {spaces: 2}, err => {
if (err) {
console.error(err)
} else {
console.log(`Collection ${collection} successfully written to ${file}.`)
}
})
})
.catch((err) => {
console.log('Error getting documents', err)
})
}
module.exports = start
Let me explain whats going on here
console.log(doc.id, ':', doc.data())
Is logging out the information how you would think you would like it to be
json.push(doc.id, ':', doc.data()) is pushing 3 elements into the array every time its called.
What you really want to do is manipulate the data properly into an object using a map function. I'm making some assumptions based on all the info I have here, but I'm guessing you want to do something like
var docs snapshot.map( doc => ({[doc.id] : doc.data()})
json.push(docs)
instead of
snapshot.forEach((doc) => {
console.log(doc.id, ':', doc.data())
json.push(doc.id, ':', doc.data())
})
You could also do (this is a bit more verbose than the map method but will essentially do the same thing. The map function is like select in sql or Linq, its handy to transform data from one form into another 😀
snapshot.forEach((doc) => {
var currentItem = {[doc.id] : doc.data()}
json.push(currentItem)
})
Since you have used some es6 notation, I'm assuming that Computed Property Names are supports, if not let me know and Ill come up with another soloution

.take() operator is not working on the Observables

The service returns me an array with 40 objects but all I need in my app are the first 5. I've made some research and I found out that the operator that fit the case is Take, but it doesn't do anything: when I call the service, it returns me all the 40 elements.
What am I doing wrong?
In the service:
getData(valueS): Observable<any> {
return Observable.from(
this.http.get<any>(`${this.URL}`)
);
}
In my component's ts:
this.dataService.getData(this.valueSelected)
.pipe(
delay(1000),
take(5)
)
.subscribe((res: any) => {
this.dataContainer = res.main;
console.log(res);
console.log(this.dataContainer);
this.buildWidget();
});
According to the docs, the .take() operator does this:
emit only the first n items emitted by an Observable
Unless your service is emitting the 40 objects one by one, then take is not a good operator to do what you want. What you need is probably just the native .slice() from javascript, which you can use Observable's .map() operator to manipulate it:
this.dataService.getData(this.valueSelected)
.pipe(
delay(1000),
map(arr=>arr.slice(0,5))//take the first five elements
)
.subscribe((res: any) => {
this.dataContainer = res.main;
console.log(res);
console.log(this.dataContainer);
this.buildWidget();
});

redux-saga takeLeading action plus additional parameter

I've implement a redux effect takeLeading that will ignore subsequent actions if the saga is currently running:
export const takeLeading = (patternOrChannel, saga, ...args) => fork(function*() {
while (true) {
const action = yield take(patternOrChannel);
yield call(saga, ...args.concat(action));
}
});
I use this for API fetching in my application, where each endpoint in my API has its own action type. So for GET methods it's useful to block if the request has already been dispatched somewhere else in the app. The saga looks like:
return function* () {
yield all([takeLeading(GET_USER_ID, callApiGen), takeLeading(GET_WIDGET_ID, callApiGen)]);
}
The obvious problem is that if I want to get two different user IDs, the second will block because it too has action type GET_USER_ID. Short of making a different action for each possible parameter, is there a way to implement some takeLeadingForFunc(<action>, (action) => <id>, saga) that allows me to keep the concise format of specifying one effect per request type but allows me to not block if the <id> is different? I was trying to wrap takeLeading with takeEvery to implement something but couldn't quite get it.
EDIT:
I got something like this to work:
export const takeLeadingForFunc = (f) => (patternOrChannel, saga, ...args) => fork(function*() {
let takeLeadings = {};
while (true) {
const action = yield take(patternOrChannel);
if (!(f(action) in takeLeadings)) {
yield call(saga, ...args.concat(action))
takeLeadings[f(action)] = yield takeLeading((ac) => f(ac) === f(action) && ac.type === action.type, saga, ...args)
}
}
});
Which takes an extractor function f that should return a primitive. This feels kind of hacky, so was wondering if there's a more idiomatic way to do this.