rxjs shortcut for mapping of one property but streaming the whole object - rxjs

I want to manipulate properties of an object but streaming the whole object
Is there a shortcut for this beauty?
Observable.of(data)
.map((data) => {data.newDueDate = this.filterDate(data.newDueDate); return data;})
.map((data) => {data.reply = this.generateReply(data.request); return data;})
...
I am searching for something like this, so i can alter the data object in clear atomic steps.
Observable.of(data)
.mapProperty('newDueDate' => this.filterDate)
.mapProperty('reply' => this.generateReply(data.request))
...

You can use do:
Observable.of(data)
.do(data => {
data.newDueDate = this.filterDate(data.newDueDate);
data.reply = this.generateReply(data.request);
})
Edit to the comment:
Observable.of(data)
.do(data => data.newDueDate = this.filterDate(data.newDueDate))
.do(data => data.reply = this.generateReply(data.request))
You can do that or create or own custom operator, but I think that's too much.

Well I think you could add both manipulations into the first map() but I agree it looks kind of lame so you might use Object.assign() for example:
Observable.of(data)
.map(d => Object.assign(d, {
newDueDate: this.filterDate(data.newDueDate),
reply: this.generateReply(data.request),
}))

Related

how to combine multiple request loop in forkJoin, is it possible?

i have observables like:
let obs1$ = of(problemsIds).pipe(flatMap(el =>
return forkJoin(el.map(id =>
this.projectsService.getProblemsChanges(+id)))))
let obs2$ = of(versionsIds).pipe(flatMap(el =>
return forkJoin(el.map(id =>
this.projectsService.getVersionById(+id)))))
then i want to get em in parallel:
return forkJoin([obs1$, obs2$])
and nothing happens.
But when ive done it with 1 obs(anyone of em), it does the result.
Why i cant combine it like that and how can i achieve it?
p.s. i know that i have to send requests as array of ids, but im interested of this case. thx
The below should work for you. Please try.
const obs1$ = this.problemIds.map(id => this.service.getProblemsChanges(+id));
const obs2$ = this.versionIds.map(id => this.service.getVersionById(+id));
return forkJoin(forkJoin(obs1$), forkJoin(obs2$)).subscribe(data => console.log(data));

Switchmap on same function

I am not a rxjs expert.
I have a method which actually does a save.
this.saveProducts(this.boxes, 'BOXES')
But there are two other different type of items that needs to use the same method for saving , just the parameter is different.
this.saveProducts(this.containers, 'CONTAINER')
In my component I have few other independent saving is happening and all these should happen one by one.
So my method look like this.
return this.service.edit(materials)
.do((data) => {
this.materials= data;
})
.switchMap(() => this.customerService.addCustomer(this.id, this.customers))
.switchMap(() => this.saveProducts(this.boxes, 'BOXES'))
.switchMap(() => this.saveProducts(this.containers, 'CONTAINER'))
.switchMap(() => this.saveProducts(this.books, 'BOOKS'))
.do(() => {
.......
}
But whats happening is it never calls the second saveProducts method unless I have a return from first one
private saveProducts(products: IProduct[], type:
Type): Observable<any> {
console.log(type);
}
Thanks for anyone who looked at it..
The answer to this issue is to return an empty observable if nothing is there to save.
if (products$.length === 0) {
return Observable.of([]);
}
Thanks guys.. Happy coding..

How to Observe Properties of Objects within an ReactiveList

I have the following Problem. I have got
aProductionOrderList = new ReactiveList<ProductionOrderViewModel>();
the ProductionOrderViewModel has a Property Itemsleft, which gets updated internally
private readonly ObservableAsPropertyHelper<int> itemsLeft;
public int ItemsLeft => this.itemsLeft.Value;
...
this.itemsLeft = this
.WhenAny(x => x.Ticks, x => x.Value)
.ToProperty(this, x => x.ItemsLeft, scheduler: DispatcherScheduler.Current);
What i want to accomplish is when ever any item in the List comes to a point where the Itemsleft property is 0, it should be removed from the List.
I tried it this way
ProductionOrderList.ItemChanged.Where(x => x.Sender.ProductionOrder.ItemsLeft ==0)
.Subscribe(v =>
{
// do stuff
});
but it did not work unfortunately.
Help is very much appreciated.
So I found a working solution, it even seems rigth and clean, though I am totally open for improvements. I have done the following
this.WhenAnyObservable(o => o.ProductionOrderList.ItemChanged)
.Where(x => x.PropertyName == "ItemsLeft")
.Select(x => x.Sender)
.Where(x => x.ItemsLeft == 0)
.Subscribe(x =>
{
ProductionOrderList.Remove(x);
});
I hope this helps others which habe a similar problem.

Elasticsearch - Default Field Name Inferrer

In 2.0 alpha for nest I am struggling to set the DefaultFieldNameInferrer to camelCase.
After figuring out how to view the 'request body' (by explicity setting the DisableDirectStreaming to true, despite the default is true...), I can see that for a request like:
...fil.Bool(b2 => b2.Must(m => m.Term(t => t.DomainName, host))))...
it is sending DomainName with a captial D:
...{"term":{"DomainName":{"value":"example.com"}}}]}...
Version 1.7 always sent camelCase and hence my mappings are all camelCase.
How can I change this back to camelCase?
Edit
Connection:
ElasticClient = new ElasticClient
(new ConnectionSettings(new Uri(WebConfigMethods.GetElasticSearchUri())).MapDefaultTypeIndices
(new ElasticsearchMethods().ElasticSearchDefaultTypeIndices)
.DisableDirectStreaming(true)
.DefaultFieldNameInferrer
(s =>
{
if (string.IsNullOrEmpty(s))
return s;
if (!char.IsUpper(s[0]))
return s;
string camelCase = char.ToLower(s[0], CultureInfo.InvariantCulture)
.ToString(CultureInfo.InvariantCulture);
if (s.Length > 1)
camelCase += s.Substring(1);
return camelCase;
}));
Request:
var result = elasticClient.Search<ADocType>
(s => s.Take(1)
.Query
(qu =>
qu.Bool
(b => b.Filter(fil => fil.Bool(b2 => b2.Must(m => m.Term(t => t.DomainName, host)))))));
What nest actually sends:
{"size":1,"query":{"bool":{"filter":[{"bool":{"must":[{"term":{"DomainName":{"value":"example.com"}}}]}}]}}}
Just adding this as a reference in case anyone stumbles across this question later.
Github issue reported here.
See 'Mpdreamz' comment.
I see two options:
implement a subclass of our JsonNetSerailizer that returns what you need for CreatePropertyName
Add a hook at the beginning of the resolve cascading flow. e.g another func on connectionsettings.

Multiple Subscriptions on one observable

I have a read-write property on my ViewModel and need two separate actions to occur when it changes :
public decimal Paid {
get { return paid; }
set { this.RaiseAndSetIfChanged(ref paid, value); }
}
...
in the ctor:
this.WhenAnyValue(pb => pb.Paid)
.Select(amount => NumberToEnglish.ToSentence(amount))
.ToProperty(this, x => x.AmountInWords, out amountInWords);
this.WhenAnyValue(pb => pb.Paid)
.Subscribe(amount => SelectedPaymentBatch.Paid = amount );
Is there a way to do this in one statement or is this the correct way to do this?
It's very much feasible to do both in one stream, e.g using Do operator (see below), but I would recommend to keep your current approach, as it correctly separates both concerns, which are unrelated but the fact they trigger on the same property (but that could change).
this.WhenAnyValue(pb => pb.Paid)
.Do(amount => SelectedPaymentBatch.Paid = amount)
.Select(amount => NumberToEnglish.ToSentence(amount))
.ToProperty(this, x => x.AmountInWords, out amountInWords);

Resources