I'm trying to learn the changes in angular 14, especially the inject()
feature where i'm able to inject modules to functions and i don't need to create special services for that.. but i think i got something wrong.
I'm trying to create some static functions to send snack messages using the package ngx-toastr
, but this package is not relevant to my question. how do I properly implement functions that show snack messages while injecting to them the required modules that they need to operate.
this is my messages.ts
file:
import {inject} from '@angular/core';
import {ToastrService} from 'ngx-toastr';
export const snackMsgSuccess = (msg: string, title?: string) => {
const toaster = inject(ToastrService);
toaster.success(msg, title, {
easeTime: 1000
});
};
export const snackMsgInfo = (msg: string, title?: string) => {
const toaster = inject(ToastrService);
toaster.info(msg, title, {
easeTime: 1000
});
};
export const snackMsgWarn = (msg: string, title?: string) => {
const toaster = inject(ToastrService);
toaster.warning(msg, title, {
easeTime: 1000
});
};
export const snackMsgError = (msg: string, title?: string) => {
const toaster = inject(ToastrService);
toaster.error(msg, title, {
easeTime: 1000
});
};
and I got the following error:
Error: Uncaught (in promise): Error: NG0203: inject() must be called from an injection context (a constructor, a factory function or a field initializer)
well... i had a problem before when i tried to have a supporting function to get route params:
export const routeParam$ = (key: string) => {
const activatedRoute = inject(ActivatedRoute);
return activatedRoute.params.pipe(
pluck(key),
filter(r => r !== null),
distinctUntilChanged()
);
};
and i was only able to use as an field initializer in a component with task: Observable<string> = routeParam$('task');
well the error message is very clear... but still.. i'm new to angular14 and i thought that inject would allow me to do that. it's not that useful for me otherwise.
for now I moved it as a service..
import {Injectable} from '@angular/core';
import {ToastrService} from 'ngx-toastr';
@Injectable({
providedIn: 'root'
})
export class MsgService {
constructor(private toaster: ToastrService) {
}
public snackMsgSuccess = (msg: string, title?: string) => {
this.toaster.success(msg, title, {
easeTime: 1000
});
};
public snackMsgInfo = (msg: string, title?: string) => {
this.toaster.info(msg, title, {
easeTime: 1000
});
};
public snackMsgWarn = (msg: string, title?: string) => {
this.toaster.warning(msg, title, {
easeTime: 1000
});
};
public snackMsgError = (msg: string, title?: string) => {
this.toaster.error(msg, title, {
easeTime: 1000
});
};
}
but is this the only way to implement it ? even in angular14 ?
runInContext
because consumers don't need to inject the injector, then call therunInContext(...)
. Assigning a local variable does the same thing, but allows the usage to be simpler IMO. Prepending the function name with "inject" might be a good convention to make it obvious that execution must occur in the constructor (or "on the class").snackMsgSuccess = injectSnackMsgSuccess()
. – Tomasine