.take() operator is not working on the Observables - angular6

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();
});

Related

Get json data in VueJS

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);
});

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
})

Best approach to deal with JSON responses in the Front End/Angular when subscribing it as a forkJoin?

I have read multiple answers to these kind of issues, and each answer has its own response;
In my case I am not getting any of those as my interfaces simply don't map the json like I want it to. I have tried multiple solutions, since working with Root-object and nested interfaces, but here I am, asking which is the best approach to deal with these kind of JSON objects in the front end, how to map it this particular one (a fork-Join). and I wanted to ask what are the real benefits of using the interfaces/classes/ maps besides the Intellisense? It has to do with data propagation?
The json structure in question:
{
Title: "",
Year: "",
Rated: "",
Released: "",
Runtime: "", 
…}
Simple as it is. But back in my service I call it with a forkjoin:
getMovies(name: string, year?: string): Observable<any> {
let shortPlot = this.http.get(
"https://www.omdbapi.com/?t=" +
name +
"&plot=short&y=" +
year +
"&apikey=[my key]"
);
let fullPlot = this.http.get(
"https://www.omdbapi.com/?t=" + name + "&plot=full&apikey=[my key]"
);
return forkJoin([shortPlot, fullPlot]);
}
The subscription in the component:
getMovie() {
this.spinner = true;
this.movieService
.getMovies(this.name.value)
.subscribe((dataList: any) => {
this.movies = Array.of(dataList[0]);
this.spinner = false;
let error: any = this.movies.map(error => error.Error);
if (error[0]) {
this.notfound = error[0];
this.error = true;
} else {
this.error = false;
this.movieRate = this.movies.map(rating => rating.imdbRating.toString());
}
})),
error => console.log(error);
}
And in the HTML I render the data like this:
<div *ngFor="let m of movies">
<h5 class="mt-0">{{m.Title}}, {{m.Year}}</h5>
</div>
So as you can see I am not working with an interface and I should. Anyone can sort me out?
Thank you
EDIT: the log after subscribe:
let's break it down,
what are the real benefits of using the interfaces/classes/ maps besides the Intellisense?
Using interfaces and classes will not just give you intellisense but will also provide static type safety for your code. Why this is important, let's say you have a interface with following structure,
export interface Demo {
field: string;
}
// in some other file 1
demo.field.substring(1, 2);
// in some other file 2
demo.field.lenght;
You are using this interface in many places in your code. Now, for some reason you get to know that the property should be number not string. So here typescript will give you all the errors at compile time only.
export interface Demo {
field: number;
}
// in some other file 1
demo.field.substring(1, 2); // error
// in some other file 2
demo.field.lenght // error
Also, after typescript transpiles it will generate javascript files, now as javascript is interpreted language, your code will not be tested until the javascript run-time actually executes the problematic line, but in typescript you will get errors in compilation stage only.
You can get away with using any everywhere, but with that you will be missing the static typings.
With interfaces and classes, you also get OOP features, such as inheritance etc.
It has to do with data propagation?
Your frond-end is never aware what type of data will be received from api. So it's developers responsibility that the received data should be mapped to some interface.
Again as mentioned above, if somehow back-end changes type of some field in received json, then it will again be caught in compile time.
In case of forkJoin which combines output of two jsons you can have two different types.
Demo
export interface Demo1 {
field1: string;
}
export interface Demo2 {
field2: number;
}
// in service layer
getData(): Observable<[Demo1, Demo2]> {
const res1 = this.http.get(...);
const res2 = this.http.get(...);
return forkJoin([res1, res2]);
}
// in component
this.dataService.getData().subscribe(res => {
// you will get type safety and intellisense for res here
console.log(res[0].field1)
})
I am not working with an interface and I should.
Yes, you should use interfaces, if you are not using using features of typescript then whats the point using it. :)

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.

Angular 4: Recreive data from MySQL to array

I have been learning Angular and I made simple app which use database request and print all information from MySQL. In my service I made this method
getCharacters(){
return this.http.get('http://localhost/something/controller/characters')
.map(
(response: Response) => {
return response.json();
}
);
}
In characters-list component I used subscribe()
this.charactersService.getCharacters().subscribe(
(characters) => {
this.characters = characters;
}
);
It works of course but it's not practical. I want to use one array to a few components so I would retrieve data from MySQL one time and use this array in all components I want to.
How to do that?