combineLatest deprecated in favor of static combineLatest - rxjs

After running the rxjs migration tool using
rxjs-5-to-6-migrate -p src/tsconfig.app.json
I'm now getting a linting error:
combineLatest is deprecated: Deprecated in favor of static
combineLatest.
Here is my code before running the migration command:
this.store.combineLatest(
this.store.select(lang.getCurrent),
this.store.select(lang.getCurrentLocale)
).subscribe(([state, currentLang, locale]) => {
this._language = session.language === currentLang ? '' : currentLang;
this._locale = session.locale === locale ? '' : locale;
});
My code after running the migration command: (currently presenting a linting error)
import {map, combineLatest} from 'rxjs/operators';
this.store.combineLatest(
this.store.select(lang.getCurrent),
this.store.select(lang.getCurrentLocale)
).subscribe(([state, currentLang, locale]) => {
this._language = session.language === currentLang ? '' : currentLang;
this._locale = session.locale === locale ? '' : locale;
});
The question was asked in this stackoverflow questions, but it was not specific enough: Angular 6 ng lint duplicate errors and warnings, combineLatest is deprecated
.

In rxjs 6.5+
import { combineLatest } from 'rxjs';
combineLatest([a$, b$, c$]);
And for most applications it's helpful to map the array of observables to a new value as well:
combineLatest([a$, b$, c$]).pipe(
map(([a$, b$, c$]) => ({
a: a$,
b: b$,
c: c$
}))
);
Also see: https://www.learnrxjs.io/learn-rxjs/operators/combination/combinelatest

Deprecated!
Please refer to ofir fridman's answer for the correct syntaxs as of RxJs 6.5
I found an answer in this article titled: RxJS 6: What's new and what has changed? ( which comes from official docs):
The solution is to convert:
import { combineLatest } from 'rxjs/operators';
a$.pipe(combineLatest(b$, c$));
into:
import { combineLatest } from 'rxjs';
combineLatest([a$, b$, c$]);

rxjs version 6.4.0
You should import map operator from RxJs operators for it to work
combineLatest(a$, b$, c$).pipe(map([a, b, c]) => treat(a, b, c))

Seems combineLatest has been deprecated and passing an array as suggested in the various answers still throws the error in rxjs v.7.0.0 Deprecation Notice
Replaced with combineLatestWith. Will be removed in v8.
For those using rxjs v.7.0.0 and above you will need to use combineLatestwith
input1Changes$.pipe(
combineLatestWith(input2Changes$)
)

import { combineLatest } from 'rxjs';
combineLatest([
this.store.select(lang.getCurrent),
this.store.select(lang.getCurrentLocale)
]).subscribe(([state, currentLang, locale]) => {
this._language = session.language === currentLang ? '' : currentLang;
this._locale = session.locale === locale ? '' : locale;
});

combineLatest with a list of subscribers:
combineLatest([aSubscriber, bSubscriber]).pipe(map((aRes, bRes)=>{
// your business logic
}));

Related

ERROR [ExceptionsHandler] no elements in sequence after upgrading to NestJS v8 and RxJS v7

After upgrading to NestJS v8, I had to upgrade my RxJS version as well from 6 to 7 then it started throwing ERROR [ExceptionsHandler] no elements in sequence error.
This is a sample method in one of the app services:
show(): Observable<any> {
return from(this.repository.fetch()).pipe(
filter((data) => data.length > 0),
map((data) => data.map((datum) => parseData(datum)),
);
}
While I had NestJS v7 and RxJS v6, the method was working just fine; in other words, if the filter operation is not passed, the map operator wouldn't be called at all and the Observable stops there.
But after upgrading to NestJS v8 and RxJS v7, if my repository does not return any data, the app starts throwing ERROR [ExceptionsHandler] no elements in sequence error.
A workaround I came up with is as follows:
show(): Observable<any> {
return from(this.repository.fetch()).pipe(
filter((data) => data.length > 0),
defaultIfEmpty([]),
map((data) => data.map((datum) => parseData(datum)),
);
}
This way the error is gone but I have two more problems:
1- the map operator still runs which I do not want
2- the second one which is way more important to me is that I have to update all my services/methods which have a validation like this which is really crazy.
my dependencies are as follows:
"dependencies": {
"#nestjs/common": "^8.4.2",
"#nestjs/core": "^8.4.2",
"rxjs": "^7.5.5"
},
We determined on Discord that an interceptor could be used here to set the defaultIfEmpty like so:
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor
} from '#nestjs/common'
import { defaultIfEmpty } from 'rxjs/operators'
#Injectable()
export class DefaultIfEmptyInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler) {
return next.handle().pipe(defaultIfEmpty([]))
}
}
And then bind it globally in the providers part of the module with:
import { DefaultIfEmptyInterceptor } from '../defaultIfEmpty.interceptor'
import { APP_INTERCEPTOR } from '#nestjs/core'
// ...
{
provide: APP_INTERCEPTOR,
useClass: DefaultIfEmptyInterceptor,
}

VueJS i18n - How to change the variable prefix in translation files

I'm doing an app using Laravel inertia and Vue, we wanted to add i18n to the app and use the same translation files for both laravel and i18n, the problem is the variable interpolation, laravel by default use :variable but vue i18n use {variable}
I tried to create a custom formatter based on what i've found here but using a custom formatter seems deprecated since I have this in my console: [intlify] Not supported 'formatter'.
I've seen on the official i18n doc that i18n is supposed to have an option for both prefix and suffix for the variable interpolation but it does not seems to exists in vue-i18n.
Does anyone ever experienced this or have an idea to solve this 'issue' ?
I run a for loop in my translation jsons and converted :variable syntax to {variable}
import {createI18n} from 'vue-i18n'
import zhCN from '../lang/zh-CN.json';
export function initializeI18n() {
let en = {};
Object.entries(zhCN).forEach(([key, value]) => {
let newEnValue = key;
en[key] = key;
if (value.includes(':')) {
let arr = value.match(/\B\:\w+/ig);
arr.forEach(matchedStr => {
let cleanMatchedStr = matchedStr.replace(':', '')
value = value.replace(matchedStr, `{${cleanMatchedStr}}`)
newEnValue = newEnValue.replace(matchedStr, `{${cleanMatchedStr}}`)
})
zhCN[key] = value;
en[key] = newEnValue;
}
})
return createI18n({
locale: window.__DEFAULT_LOCALE__,
fallbackLocale: window.__FALLBACK_LOCALE__,
messages: {
'zh-CN': zhCN,
en
},
silentFallbackWarn: true,
silentTranslationWarn: true
});
}
This was, putting in es.js
"Hello :name": "Hola :name"
should work as expected:
{{ $t("Hello :name", {name: 'world'}) }},

i get error 'FileProvider' of undefined using record function with nativescript-videorecorder

i need help.
TypeError: Cannot read property 'FileProvider' of undefined
I get that error when i try to record.
Code:
const options: VideoRecorderOptions = {
hd: true,
saveToGallery: true
}
const videorecorder = new VideoRecorder(options)
videorecorder.record().then((data) => {
console.log(data.file)
}).catch((err) => {
console.log(err)
})
It seems to be Android X compatibility issue, the plugin author will have to update the plugin to support {N} 6.x and later.
android.support.v4.content.FileProvider is now androidx.core.content.FileProvider. You may update the code and compile it locally as a workaround.

How can i rewrite the following code with switchmap

Hi I have a small code snippet using rxjs library as follows. It is working fine . However I would like to re write it using switchmap . I tried all option however i am getting an error . was wondering if someone could help me out .
this.campaignControl.valueChanges.subscribe(
(value) => {
this.flightsService.getUnpaginatedFlightsWithinRange(
{
campaignId : value,
jobStatuses: this.flightStatusIds,
rangeStartDate:
(this.rangeControl.value[0]).toISOString(),
rangeEndDate: (this.rangeControl.value[1]).toISOString()
}
).subscribe(
(flightsUnpaginated) => {
this.flights = flightsUnpaginated;
}
);
}
);
thank you
I believe you're looking for something like this:
this.campaignControl.valueChanges.pipe(
switchMap(value => this.flightsService.getUnpaginatedFlightsWithinRange({
campaignId : value,
jobStatuses: this.flightStatusIds,
rangeStartDate: (this.rangeControl.value[0]).toISOString(),
rangeEndDate: (this.rangeControl.value[1]).toISOString()
}),
tap(flightsUnpaginated => this.flights = flightsUnpaginated)
).subscribe();

Says Jasmine spy is not being called, but I can see that its being called

I can't figure out why Jasmine is claiming that the function I'm spying on isn't being called, especially since it is logging in buildLinksObj when called through and not calling when I remove .and.callThrough() I feel like I've written similar code a bunch of times before without any problem. I'm using Jasmine 2.9
The error message I'm getting is:
1) addToLinks should call buildLinksObj if its given an object with children
it should add the personalized links to PageApp.meta.analytics.links
Expected spy buildLinksObj to have been called.
at UserContext.<anonymous> (http://localhost:9877webpack:///tests/specs/common/FetchPersonalContent.spec.js:854:0 <- tests/app-mcom.js:104553:48)
Here's the except of my code:
FetchPersonalContent.js
const buildLinksObj = (responseObj = {}, targetObj, PageApp) => {
console.log('it logs in buildLinksObj') // This is logging!
}
const addToLinks = (responseArr, personalizedLinks) => {
responseArr.forEach((media) => {
const type = media.type;
const typeObj = media[type];
buildLinksObj(typeObj, personalizedLinks, PageApp);
if (typeObj && typeObj.children) {
console.log('has children!')
console.log('typeObj.children is: ', typeObj.children);
typeObj.children.forEach((child) => {
console.log('has a child')
buildLinksObj(child, personalizedLinks, PageApp);
console.log('buildLinksObj was definitely called. what the heck?')
});
}
});
}
export {buildLinksObj, addToLinks, FetchPersonalContent as default,
};
FetchPersonalContent.spec.js
import * as FetchPersonalContent from '../../../src/FetchPersonalContent'; // my path is definitely correct
describe('it should add the personalized links to PageApp.meta.analytics.links', () => {
it('addToLinks should call buildLinksObj if its given an object with children ', () => {
spyOn(FetchPersonalContent, 'buildLinksObj').and.callThrough();
FetchPersonalContent.addToLinks([{
"personalId": 30718,
"type": "carousel",
"carousel": {}
}], {});
expect(FetchPersonalContent.buildLinksObj).toHaveBeenCalled();
});
});
I'd really appreciate any help!
I have a feeling FetchPersonalContent.buildLinksObj in the spec file is not pointing to the same instance as buildLinksObj in the FetchPersonalContent.js file.
Why is export {FetchPersonalContent as default} required? I am assuming you have shared the complete content of FetchPersonalContent.js in your question.
Possible solutions:
You can try removing FetchPersonalContent from the export statement.
Or
Instead of
export {buildLinksObj, addToLinks, FetchPersonalContent as default,
};
You can directly export the constants in FetchPersonalContent.js file.

Resources