RxJs: Map to anonymous type object - rxjs

I've created this Observable:
private accounts$: Observable<{type: string, alias: string}>;
I need to map an Array<Account> to an stream of {type, alias} object. Up to now, I've tried this:
this.accounts$ = this.store$
.select(fromRoot.getDBoxAccountEntities)
.flatMap(accounts => accounts.map(account => {type: 'dbox', alias: account.dboxAccount}))
...
However I'm getting compilation error messages.
Any ideas?

You are returning an object from your arrow function but the brackets suggest function body. You need () around your returned object:
.flatMap(accounts => accounts.map(account => ({type: 'dbox', alias: account.dboxAccount})))

Related

async function as type in hacklang

I am trying to build a shape where key is string and value is function. This works fine for regular functions but gives error for async functions. Following is what I am trying to do
const type TAbc = shape(
'works' => (function (): string),
'doesnt_work' => (async function(): Awaitable<string>)
);
This results in error A type specifier is expected here.Hack(1002)
Encountered unexpected text async, was expecting a type hint.Hack(1002)
Is this illegal in Hacklang? If yes then would like to know why?
async function (): T is illegal in Hacklang. The suggested way to do this is by defining it in the return type, Awaitable<T>.
So to get this working we can do this
const type TAbc = shape(
'sync' => (function (): string),
'async' => (function(): Awaitable<string>)
);
And while initialising an instance of this type we can internally call an async function. For eg:
$abc = shape(
'async' => function(): Awaitable<string> {
return someAsyncFunction();
});

RxJS - Iterate over returned data from ajax

I am using RxJS Ajax() to return a bunch of GitHub users. I want to iterate over each one and just get the login names from each user. I am able to iterate over a local array of objects, but not if that array of objects came from Ajax, whether or not I force it to be a stream with RxJS from().
// from() the array of objects (locally defined)
let localArrayOfObj = from([
{ login: 'Barbara Holland', loggedIn: false, token: null },
{ login: 'Joyce Byers', loggedIn: true, token: 'abc' },
{ login: 'Nancy Wheeler', loggedIn: true, token: '123' }
]);
// Return the "login" names:
localArrayOfObj.pipe(
map((data) => data.login)
).subscribe(console.log); // This returns the login names
// from() the array of objects (returned by Ajax)
const githubUsers = `https://api.github.com/users?per_page=2`;
const arrayFromAjax = from(ajax.getJSON(githubUsers));
arrayFromAjax.subscribe(console.log);
// Trying the same to return the "login" names:
arrayFromAjax.pipe(
map((data) => data.login)
).subscribe(console.log); // This is undefined
I'm putting the results of the Ajax call through RxJS from() so both arrays are treated the same, however the same undefined results occur if I skip from() and just do
const arrayFromAjax = ajax.getJSON(githubUsers);
instead of
const arrayFromAjax = from(ajax.getJSON(githubUsers));
How is an array of objects from Ajax() different than a similar locally defined array of objects? And how can I iterate over the Ajax results?
The from() operator creates an observable that emits the provided values one at at time, so you are not receiving an array, you are receiving individual objects.
ajax.getJSON(githubUsers) returns an array of objects. This is why you are seeing differences between these two cases.
You can alter your test case with local array to the following the match the same shape:
let localArrayOfObj = from([
[
{ login: 'Barbara Holland', loggedIn: false, token: null },
{ login: 'Joyce Byers', loggedIn: true, token: 'abc' },
{ login: 'Nancy Wheeler', loggedIn: true, token: '123' }
]
]);
In your code here: data is an array, so if you want to modify the elements individually you can do something like:
arrayFromAjax.pipe(
map((dataArray) => dataArray.map(data => data.login))
).subscribe(console.log); // This is undefined

compilation problem/error while using an rxjs switchmap

Hi i am getting an error in my code . I have an angular 5 formGroup and i am trying to use the pipe operation and switchMap inside.
However it give me an error. The following is my code snippet.
this.formGroup.valueChanges.pipe(
switchMap(
(formValue) => {
console.log(formValue);
}
)
).subscribe();
the error i is as below
Argument of type '(formValue: any) => void' is not assignable to parameter of type '(value: any, index: number) => ObservableInput<{}>'.
Type 'void' is not assignable to type 'ObservableInput<{}>'.ts(2345)
really appreciate any help
thank you
You have to return an observable in the switchMap. switchMap switches to a new observable and you can do it conditionally based on the previous value.
If you want to just console.log, I would use tap.
this.formGroup.valueChanges.pipe(
tap(
(formValue) => {
console.log(formValue);
}
),
).subscribe();
====================== Edit ==========================
I assume this.generatePerformanceGraph(formValue); is a regular function and it doesn't return an observable, then you can do it in the subscribe.
this.formGroup.valueChanges.pipe(
tap( // you can remove this tap, it is just for logging
(formValue) => {
console.log(formValue);
}
),
).subscribe(formValue => {
this.generatePerformanceGraph(formValue);
});

How to wrap an object into a function return this object using jscodeshift

Let's say I have the following file
export default {
foo: 'bar'
}
How can I transform this file using jscodeshift so it wraps the object into function like this:
export default () => ({
foo: 'bar'
})
My main problem is how to use the api.jscodeshift.arrowFunctionExpression(), especially how to create the function body. Cause I think all I need to do, is to replace the ObjectExpression with a function that has the ObjectExpression as its body.
Another option is to use j.template.expression which is a tagged template that lets you interpolate JavaScript with existing nodes:
Complete example:
return j(file.source)
.find(j.ExportDefaultDeclaration)
.find(j.ObjectExpression)
.replaceWith(
path => j.template.expression`theme => ${path.node}`
)
.toSource();
Found out by myself. arrowFunctionExpression take a list params and then a blockStatement. This will generate the function:
const fn = j.arrowFunctionExpression(
[{ type: "Identifier", name: "theme" }],
j.blockStatement([j.returnStatement(stylesObject)])
);
Then create a new exportDefaultDeclaration and pass the function to it.
const e = j.exportDefaultDeclaration(fn)
return j(e).toSource();

RxJs: How to combine two observable into a new observable with different type

I'm very new to RxJs and NgRx store , I'm want to create an #Effect with combination of two observables (very difficult to explain):
My interfaces looks like:
export interface ProductDetails {
product: Product;
productBody: ProductBody;
}
export interface ProductBody{
id: string;
body: string;
}
I'm trying to create a new objectproductDetails and set it's properties.
properties are product which payload has product and productBody which gets it from productService(id) (It returns observable<productBody>)
This effect should return observable<productDetails>
#Effect()
getProductDetails$ = this.actions$
.ofType(ProductActions.GET_STEP)
.map(action => action.payload)
.flatMap(s => {
let body;
this.productService.getStepBody(s.id).subscribe(x => body = x);
return Observable.of({
step: s,
productBody: body
});
})
.map(res => this.productActions.getProductDetailsSuccess(res));
this returns:Object {productBody: undefined, product: Object}
I understand why is returning undefined for productBody but not sure how to fix it. I tried using zip, switchMap and etc but no chance!
Here is what you can do.
You want to flatMap over the original observable to get the payload.id to give it to the getStepBody observable.
Then, inside the flatMap, you want to map on the getStepBody observable to return a new value that is a composite object of the payload and the response of the getStepBody.
Finally subscribe to get the final result.
It looks something like this:
getProductDetails$ = this.actions$
.ofType(ProductActions.GET_STEP)
.map(action => action.payload)
.flatMap(payload => this.productService.getStepBody(payload.id).map(body => ({step: payload, productBody: body})))
.subscribe(res => this.productActions.getProductDetailsSuccess(res)); //res is an object of {step: payload, productBody: body}
If you are not wanting to return the whole object into a single function in the subscribe function, you could destructure the values to make them easier to consume separately. To that change the subscribe line to:
.subscribe(({step, body}) => {//do something with each value});

Resources