angular2firebase - multiple instances using Angular 6 - angularfire2

I'm upgrading to Angular 6 using AngularFire2. My app referenced 2 Firebase projects using code like this to create the database reference:
public initFirebaseApp(config: FirebaseAppConfig, firebaseAppName: string) {
this._db = new AngularFireDatabase(_firebaseAppFactory(config, firebaseAppName));
}
This code is now broken. I get this:
ERROR in src/app/services/firebase.service.ts(24,25): error TS2554: Expected 5 arguments, but got 1.
Thanks!

AngularFire now support many more configuration objects via Injection now, which is why it's expecting more arguments. It currently takes:
constructor(
#Inject(FirebaseOptionsToken) options:FirebaseOptions,
#Optional() #Inject(FirebaseNameOrConfigToken) nameOrConfig:string|FirebaseAppConfig|undefined,
#Optional() #Inject(RealtimeDatabaseURL) databaseURL:string,
#Inject(PLATFORM_ID) platformId: Object,
zone: NgZone
)
Though now that we support dependency injection, I wouldn't suggest directly initializing like you are to support multiple apps. We have an open issue for documenting this but you can now inject different FirebaseOptions via the FirebaseOptionsToken into different components, if you need multiple databases in the same component use something like this:
#Injectable()
export class AngularFireDatabaseAlpha extends AngularFireDatabase { }
#Injectable()
export class AngularFireDatabaseBeta extends AngularFireDatabase { }
export function AngularFireDatabaseAlphaFactory(platformId: Object, zone: NgZone): Project1AngularFireAuth {
return new AngularFireDatabaseAlpha(environment.firebase[0], 'alpha', undefined, platformId, zone)
}
export function AngularFireDatabaseBetaFactory(platformId: Object, zone: NgZone): Project2AngularFireAuth {
return new AngularFireDatabaseBeta(environment.firebase[1], 'beta', undefined, platformId, zone)
}
#NgModule({
...,
providers: [
...,
{ provide: AngularFireDatabaseAlpha, deps: [PLATFORM_ID, NgZone], useFactory: AngularFireDatabaseAlphaFactory },
{ provide: AngularFireDatabaseBeta, deps: [PLATFORM_ID, NgZone], useFactory: AngularFireDatabaseBetaFactory },
...
],
...
})
Then you can just rely on Dependency Injection to get AngularFireDatabaseAlpha and AngularFireDatabaseBeta into your component.

Related

inject nestjs service to build context for graphql gateway server

In app.module.ts I have the following:
#Module({
imports: [
...,
GraphQLModule.forRoot<ApolloGatewayDriverConfig>({
server: {
context: getContext,
},
driver: ApolloGatewayDriver,
gateway: {
buildService: ({ name, url }) => {
return new RemoteGraphQLDataSource({
url,
willSendRequest({ request, context }: any) {
...
},
});
},
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'iam', url: API_URL_IAM },
],
})
},
}),
]
...
})
here getContext is just a regular function which is not part of nestjs context (doesn't have injection, module capability) like below:
export const getContext = async ({ req }) => {
return {}
}
Is there any way to use nestjs services instead of plain old functional approach to build the context for graphql gateway in nestjs?
Thanks in advance for any kind of help.
I believe you're looking to create a service that is #Injectable and you can use that injectable service via a provider. What a provider will do is satisfy any dependency injection necessary.
In your scenario, I would import other modules as necessary. For building context, I would create a config file to create from env variables. Then create a custom provider that reads from the env variables and provides that implementation of the class/service to the other classes as their dependency injection.
For example, if I have a graphQL module. I would import the independent module. Then, I would provide in the providers section, the handler/service classes and the dependencies as an #injectable. Once your service class is created based on your config (which your provider class would handle), you would attach that service class to your GraphQL class to maybe lets say direct the URL to your dev/prod envs.

ngxs: Store not initialized when injected

I am using ngxs 3.7.5 with Angular 14
// single slice
#State<EnvironmentStateModel>({
name: 'environment',
defaults: {
productionBuild: environment.production,
internalPlatform: detectInternalPlatform(window.location.hostname, window.location.port),
platform: detectPlattform(),
appVersion: environment.appVersion
}
})
#Injectable()
export class EnvironmentState {
}
I am injecting the store into a HttpInterceptor
export class MessageHeaderInterceptor implements HttpInterceptor {
constructor(private userService: UserService, private store: Store) {
console.log('constructor', this.store.selectSnapshot((appState: AppState) => appState));
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('intercept', this.store.selectSnapshot((appState: AppState) => appState));
//...
}
}
The console statement in the constructor shows {}, also the console statement in the first call to intercept. However consecutive calls to intercept show { environment: ... } that is with the environment slice properly initialized. I expect the store to be properly initialized when using it the first time. What am I doing wrong?
When you include the NgxsModule in the import, the EnvironmentState should be passed to the NgxsModule's .forRoot() function (if it's a root store), or .forFeature() function (if it's a lazy-loaded store).
You can find more details here:
https://www.ngxs.io/getting-started/installation
https://www.ngxs.io/advanced/lazy

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

InjectionToken: Nest can't resolve dependencies

I have a CheckModule which accepts configuration in the forRoot method using a constant CHECK_OPTIONS:
#Module({})
export class CheckModule {
static forRoot(options?: CheckOptions): DynamicModule {
return {
module: CheckModule,
providers: [
{
provide: CHECK_OPTIONS,
useValue: options,
},
CheckService,
],
exports: [CheckService],
};
}
}
My CheckService uses the options:
#Injectable()
export class CheckService {
...
constructor(#Inject(CHECK_OPTIONS) options: CheckOptions) {}
...
Whenever I debug the application, everything is working fine. But, once I build for production and serve it on Heroku I get an error.
# Production build
nx build $PROJECT_NAME --prod
# Serving the app
node dist/apps/worker/main.js
I get an error:
ERROR [ExceptionHandler] Nest can't resolve dependencies of the CheckService (?). Please make sure that the argument CHECK_OPTIONS at index [0] is available in the CheckModule context.
Am I missing something here? I'm kind of clueless...
Seems like your module needs to be global.
Try adding #Global() decorator before #Module({}).
In my app.module I imported the CheckModule as:
imports: [
CheckModule.forRoot(),
...
]
This method had an optional parameter for CheckOptions:
forRoot(options?: CheckOptions) { ... }
However my CheckService expects a CHECK_OPTIONS which is not optional. This is what caused the error. Correctly marking this InjectionToken as #Optional() resolved this issue.
So, I've changed the code from:
constructor(#Inject(CHECK_OPTIONS) options?: CheckOptions) {}
To:
constructor(#Optional() #Inject(CHECK_OPTIONS) options?: CheckOptions) {}
^^^^^^^^^^^
See https://docs.nestjs.com/providers#optional-providers for more information about the #Optional() decorator.
I had the same issue, fixed it by moving adding all the providers to exports of the dynamic module also. in you case add:
exports: [ {
provide: CHECK_OPTIONS,
useValue: options,
},
CheckService]

Spartacus Storefront Multisite I18n with Backend

We've run into some problems for our MultiSite Spartacus setup when doing I18n.
We'd like to have different translations for each site, so we put these on an API that can give back the messages dependent on the baseSite, eg: backend.org/baseSiteX/messages?group=common
But the Spartacus setup doesn't let us pass the baseSite? We can
pass {{lng}} and {{ns}}, but no baseSite.
See https://sap.github.io/spartacus-docs/i18n/#lazy-loading
We'd could do it by overriding i18nextInit, but I'm unsure how to achieve this.
In the documentation, it says you can use crossOrigin: true in the config, but that does not seem to work. The type-checking say it's unsupported, and it still shows uw CORS-issues
Does someone have ideas for these problems?
Currently only language {{lng}} and chunk name {{ns}} are supported as dynamic params in the i18n.backend.loadPath config.
To achieve your goal, you can implement a custom Spartacus CONFIG_INITIALIZER to will populate your i18n.backend.loadPath config based on the value from the BaseSiteService.getActive():
#Injectable({ providedIn: 'root' })
export class I18nBackendPathConfigInitializer implements ConfigInitializer {
readonly scopes = ['i18n.backend.loadPath']; // declare config key that you will resolve
readonly configFactory = () => this.resolveConfig().toPromise();
constructor(protected baseSiteService: BaseSiteService) {}
protected resolveConfig(): Observable<I18nConfig> {
return this.baseSiteService.getActive().pipe(
take(1),
map((baseSite) => ({
i18n: {
backend: {
// initialize your i18n backend path using the basesite value:
loadPath: `https://backend.org/${baseSite}/messages?lang={{lng}}&group={{ns}}`,
},
},
}))
);
}
}
and provide it in your module (i.e. in app.module):
#NgModule({
providers: [
{
provide: CONFIG_INITIALIZER,
useExisting: I18nBackendPathConfigInitializer,
multi: true,
},
],
/* ... */
})
Note: the above solution assumes the active basesite is set only once, on app start (which is the case in Spartacus by default).

Resources