Using Custom Pipes in services in angular2 - angular2-pipe

I want to call the my custom pipe inside Injectable service. I checked many threads in stackoverflow. But they talk about using custom pipes inside a component. Can u please help me here, any helpful link will be fine. Below is my custom pipe file:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({ name: 'unit' })
export class UnitPipe implements PipeTransform {
transform(val,unit, args) {
if(unit=='Metric') {
return val * 2;
}
else {
return val * 4;
}
}
}
And Iam trying to access this pipe in my service:
import { Injectable } from '#angular/core';
import { Http, Response, Headers, RequestOptions } from '#angular/http';
import { UnitPipe } from '../pipes/UnitPipe';
#Injectable()
export class SomeService {
constructor(http: Http, unitPipe: UnitPipe) {
this.http = http;
this.unitPipe = unitPipe;
}
transformUnit() {
return this.unitPipe.transform('10', 'Metric');
}
}
I have specified this in app.module.js
declarations: [UnitPipe],
providers: [UnitPipe]
And in my component.js, I am calling this service method & just checking the output in console:
import { Component, OnInit, EventEmitter, Input } from '#angular/core';
import { SomeService } from '../../services/SomeService';
#Component({
})
export class SomeClass implements OnInit {
constructor(someService: SomeService) {
this.someService = someService;
}
ngOnInit(): void {
console.log(this.someService.transformUnit());
}
}
But Iam getting below error
One more thing is, my plan is to call transformUnit method inside my service file 'SomeService', may be onload, where the function definition is present. Any thought on this?
Thank you.

Your pipe transform function expects 3 parameters:
transform(val,unit, args) {
...
}
You're providing only 2 parameters to it:
transformUnit() {
return this.unitPipe.transform('10', 'Metric');
}
Best solutions I can suggest is using an Optional/Default parameter:
Optional parameter - Change args to args?
OR
Default parameter - Change args to args = null // or some other default value
This will allow you to call the pipe function with 2 params, so no need for code changing in your service.
You can see in this TypeScirpt-Functions link, section called Optional and Default Parameters for more details.
Created a simple StackBlitz DEMO with your code to this in action. Initially you will see the error in SomeService file. Just change the pipe args param accordingly. refresh the page. The error is gone in SomeService.

Related

How to use adoptedStyleSheets in lit

Refer to this document,
https://lit.dev/docs/api/styles/#adoptStyles
I am not able to figure out the way to use it.
Seems like I can use following way to do the import.
import styleSheet from '#material/data-table/dist/mdc.data-table.css' assert { type: 'css' };
connectedCallback() {
super.connectedCallback();
this.renderRoot.adoptedStyleSheets = [styleSheet];
}
you can use static get styles inside your class
import { adoptStyles, LitElement } from 'lit';
class youComp extends LitElement {
static get styles(){
return [adoptStyles] /* you can return array of styles */
}
}
This should do the job

NestJS - How to create wrapping service over jwt service (from jwt module)

Sorry for my bad english, I'm from Ukraine :)
Could you tell me how can I create my own service, that extends of Jwt service provided jwt module from npm package? I want to create my own JwtService for catch errors and isolate duplicate logic for token creation and verification. Please, help me how can I do it. Code samples attached.
import { BadRequestException, Injectable } from '#nestjs/common';
import { JwtService as NestJwtService, JwtVerifyOptions } from '#nestjs/jwt';
#Injectable()
export class OwnJwtService extends NestJwtService {
constructor() {
super({});
}
async verifyAsync<T>(token: string, options?: JwtVerifyOptions): Promise<T> {
try {
const res = await super.verifyAsync(token, options);
console.log('res', res);
return res;
} catch (error) {
// My own logic here ...
throw new BadRequestException({
error,
message: 'Error with verify provided token',
});
}
}
}
or maybe I need to inject nestjs jwt service to my own service ? example:
import { BadRequestException, Injectable } from '#nestjs/common';
import { JwtService as NestJwtService, JwtVerifyOptions } from '#nestjs/jwt';
#Injectable()
export class OwnJwtService {
constructor(private readonly jwtService: NestJwtService) {}
async verifyAsync<T>(token: string, options?: JwtVerifyOptions): Promise<T> {
try {
const res = await this.jwtService.verifyAsync(token, options);
console.log('res', res);
return res;
} catch (error) {
throw new BadRequestException({
error,
message: 'Error with verify provided token',
});
}
}
}
and
import { JwtModule as NestJwtModule } from '#nestjs/jwt';
import { ConfigModule, ConfigService } from '#nestjs/config';
import { Module } from '#nestjs/common';
import { OwnJwtService } from 'src/modules/jwt/jwt.service';
#Module({
imports: [
NestJwtModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
signOptions: {
expiresIn: process.env.JWT_EXPIRES_IN,
},
secret: process.env.JWT_SECRET,
secretOrPrivateKey: process.env.JWT_SECRET,
}),
inject: [ConfigService],
}),
],
providers: [OwnJwtService],
exports: [OwnJwtService],
})
export class JwtModule {}
but it doesn't work for me, and I have similar errors:
Error: Nest can't resolve dependencies of the OwnJwtService (?). Please make sure that the argument JwtService at index [0] is available in the AuthModule context.
First, notice that the JwtModule basically creates a module based on jsonwebtoken and your custom errors aren't meant to be dealt inside it.
Second, when you use registerAsync you are meant to get your ENV variables with the ConfigService as in configService.get('JWT_SECRET').
Third, your question is inefficient. The JwtModule already does everything you need. You just need to implement it. Again, just think of it as the jsonwebtoken package adapted for Nest. That's it.
On the signup, login and refreshtoken (if existing) routes you sign when you create a new token.
And in your requests middleware you verify.
One kind of a big issue with Nest is its documentation. It doesn't have everything you need. There might be more than one way to verify a route, but the most straightforward is just using Express middleware, as in a typical Express app.
To do this, you need to implement it in the AppModule like this:
#Module(...)
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer): MiddlewareConsumer | void {
consumer.apply(cookieParser(), AuthMiddleware).forRoutes('/');
}
}
In this example, I'm also registering the module cookieParser() because I send the tokens in a cookie. Other cookie modules will do, too. Both the NestModule and the MiddlewareConsumer come from #nestjs/common.
AuthMiddleware is a middleware I made using this skeleton...
export class AuthMiddleware implements NestMiddleware {
constructor(
private readonly configService: ConfigService,
private readonly jwtService: JwtService
) {}
async use(req: Request, res: Response, next: NextFunction) {
const { yourJwtToken } = req.cookies;
const isValidToken = this.jwtService.verify(
yourJwtToken,
this.configService.get('JWT_SECRET'),
);
if (!isValidToken) throw new UnauthorizedException();
// etc...
next();
}
}
Finally, what you might be asking to, is to apply the AuthGuard.
If you use the Passport ones, you need just to follow the documentation to apply them. They already throw errors if you. If you want to change it, just rewrite its methods.
You can also do it manually. Just use the console to generate a guard, and in there you can check authentication context.switchToHttp().getRequest() and return a boolean after checking the credentials and use the constructor to check the permissions if you want.
You might also skip the middleware config from above and implement the logic inside the guard if you will.
Again, I don't really think changing the JwtModule is the best idea here.

how properly save data to MongoDb throw Spring-data in no-blocking stack using CompletableFuture

The question could be summarized: how properly save data to MongoDb throw Spring-data in no-blocking stack using CompletableFuture (i.e. Spring Webflux + reactive.ReactiveCrudRepository + java.util.concurrent)?
I have struglled for the last three days studing and searcing around and reading several tutorials in order to find a recommended way or at least a "north path" to persist data when someone wants to use CompletableFuture for that. I could reach the code bellow succesfully working but I am not sure if I am doing some weird stuff.
Basically, I want to use CompletableFuture because I want to chain futures. Let say, save firstly in MongoDb and if well-done then "thenAcceptAsync" and finally "thenCombine" them.
Well, ReactiveCrudRepository.save returns Mono<> and I must subscribe in order to effectivelly save it. Additionally Mono<>.subscribe() returns dispose whic I understand I can use to cancel it let's say if the thread takes too long because MongoDb is out for instance or any other exception. SO far so good.
What is unclear to me is if I am not messing up the idea of using using saving the data which blocks in assyncronous method. Since my puporse is leave to "future" resolution am I am blocking during the save method bellow and completely losing the benefitis of saving in different thread and get a future result?
Code saving properly to MongoDb but not clear to me if it is really "no-blocking" approach. Note that completableFuture.get() is commented since I don't need it in onder to effectively save my data
#Async("taskExecutor")
public void transferirDisposableReturnedSupplyAsync(Extrato e) throws InterruptedException, ExecutionException {
CompletableFuture<Disposable> completableFuture = CompletableFuture
.supplyAsync(() -> extratoRepository.save(e).subscribe());
//completableFuture.get(); unnecessary since subscribe() above already saved it
}
In case it is relevant:
Repository:
import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import com.noblockingcase.demo.model.Extrato;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.data.domain.Pageable;
public interface ExtratoRepository extends ReactiveCrudRepository<Extrato, String> {
#Query("{ id: { $exists: true }}")
Flux<Extrato> retrieveAllExtratosPaged(final Pageable page);
}
AsyncConfiguration:
import java.util.concurrent.Executor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
// The #EnableAsync annotation enables Spring’s ability to run #Async methods in a background thread pool.
// The bean taskExecutor helps to customize the thread executor such as configuring number of threads for an application, queue limit size and so on.
// Spring will specifically look for this bean when the server is started.
// If this bean is not defined, Spring will create SimpleAsyncTaskExecutor by default.
#Configuration
#EnableAsync
public class AsyncConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(AsyncConfiguration.class);
#Bean(name = "taskExecutor")
public Executor taskExecutor() {
LOGGER.debug("Creating Async Task Executor");
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("ExtratoThread-");
executor.initialize();
return executor;
}
}
*** added
import { Injectable, NgZone } from '#angular/core';
import { Observable } from 'rxjs';
import { Extrato } from './extrato';
#Injectable({
providedIn: "root"
})
export class SseService {
extratos: Extrato[] = [];
constructor(private _zone: NgZone) { }
getServerSentEvent(url: string): Observable<any> {
this.extratos = [];
return Observable.create(observer => {
const eventSource = this.getEventSource(url);
eventSource.onmessage = event => {
this._zone.run(() => {
let json = JSON.parse(event.data);
this.extratos.push(new Extrato(json['id'], json['description'], json['value'], json['status']));
observer.next(this.extratos);
});
};
eventSource.onerror = (error) => {
if (eventSource.readyState === 0) {
console.log('The stream has been closed by the server.');
eventSource.close();
observer.complete();
} else {
observer.error('EventSource error: ' + error);
}
}
});
}
private getEventSource(url: string): EventSource {
return new EventSource(url);
}
}

ReflectiveInjector throws InvalidProviderError

I am trying to inject 2 services into generic classes using ReflectiveInjector as seen in this SO
The first time I call ReflectiveInjector on DebugService it works completely fine, however if I then replace this with CourseService, I recieve the following InvalidProviderError:
Uncaught InvalidProviderError_nativeError: Error: Invalid provider - only instances of Provider and Type are allowed, got: undefined
This is the generic class where I am trying to inject the services.
Media.ts
////////////////////////////////////////////////////////////////////////////////////////
import { ReflectiveInjector } from '#angular/core';
// other imports
////////////////////////////////////////////////////////////////////////////////////////
import { CourseService , DebugService } from 'app/services';
//other imports
////////////////////////////////////////////////////////////////////////////////////////
export class Media {
private sanitizer: DomSanitizer;
private courseService: CourseService;
private debug: DebugService;
constructor(_audio: File[], _images: File[], _videos: File[] ) {
// works fine
var injector = ReflectiveInjector.resolveAndCreate([DebugService]);
this.debug = injector.get(DebugService);
// throws InvalidProviderError
var injector2 = ReflectiveInjector.resolveAndCreate([CourseService]);
this.courseService = injector2.get(CourseService);
}
The 2 services are as follows:
debug.service.ts
////////////////////////////////////////////////////////////////////////////////////////
import { Injectable } from '#angular/core';
////////////////////////////////////////////////////////////////////////////////////////
import { environment } from '../../environments/environment';
////////////////////////////////////////////////////////////////////////////////////////
#Injectable()
export class DebugService {
constructor() {
/*stuff*/
}
}
course-service.service.ts
////////////////////////////////////////////////////////////////////////////////////////
import { Injectable, EventEmitter, Output } from '#angular/core';
import { Router } from '#angular/router';
import { Title, DomSanitizer, SafeResourceUrl, SafeUrl} from '#angular/platform-browser';
////////////////////////////////////////////////////////////////////////////////////////
import { DebugService } from 'app/services';
////////////////////////////////////////////////////////////////////////////////////////
#Injectable()
export class CourseService {
#Output() preloadData = new EventEmitter<any>();
// Constructor 1 - called on instantiation of class
constructor(
private sanitizer: DomSanitizer,
private router: Router,
private titleService: Title,
private debug: DebugService
) { /*stuff*/ }
These services were successfully being used in the Media class prior, when I was manually passing CourseService and DebugService as params to the Media constructor, however wanted to get away from this as it seemed very 'clunky' compared to this more streamlined approach.
i.e.
export class Media {
/*stuff*/
constructor(_audio: File[], _images: File[], _videos: File[], _courseService: CourseService, _debugService: DebugService ) { /*stuff*/ }
}
Media is currently defined within another class's constructor:
var preloader = new Preloader(
new Media(
// Audio Files
[
new File(0, './app/assets/video/Example1.mp3')
],
// Image Files
[
],
// Video Files
[
new File(0, './app/assets/video/Example1.mp4')
]
)
//...

Exchange Data between multi step forms in Angular2: What is the proven way?

I can imagine following approaches to exchange Data between multi step forms:
1) Create a component for each form step and exchange data between components over #input, #output (e.g. you cannot change from step5 to 2)
2) Use the new property data in the new router (see here) (e.g. you cannot change from step5 to 2))
3) A shared Service (Dependency Injection) to store data (Component Interaction) (e.g. you can change from step5 to 2)
4) New rudiments with #ngrx/store (not really experienced yet)
Can you give some "gained experience values", what do you use and why?
See my edit below.
Using SessionStorage is not strictly the 'angular' way to approach this in my opinion—a shared service is the way to go. Implementing routing between steps would be even better (as each component can have its own form and different logic as you see fit:
const multistepRoutes: Routes = [
{
path: 'multistep',
component: MultistepComponent,
children: [
{
path: '',
component: MultistepBaseComponent,
},
{
path: 'step1',
component: MultistepStep1Component
},
{
path: 'step2',
component: MultistepStep2Component
}
]
}
];
The service multistep.service can hold the model and implement logic for components:
import { Injectable, Inject } from '#angular/core';
import { Router } from '#angular/router';
#Injectable()
export class MultistepService {
public model = {};
public baseRoute = '/multistep';
public steps = [
'step1',
'step2'
];
constructor (
#Inject(Router) public router: Router) { };
public getInitialStep() {
this.router.navigate([this.baseRoute + '/' + this.steps[0]]);
};
public goToNextStep (direction /* pass 'forward' or 'backward' to service from view */): any {
let stepIndex = this.steps.indexOf(this.router.url.split('/')[2]);
if (stepIndex === -1 || stepIndex === this.steps.length) return;
this.router.navigate([this.baseRoute + '/' + this.steps[stepIndex + (direction === 'forward' ? 1 : -1)]]);
};
};
Good luck.
EDIT 12/6/2016
Actually, now having worked with the form API for a while I don't believe my previous answer is the best way to achieve this.
A preferrable approach is to create a top level FormGroup which has each step in your multistep form as it's own FormControl (either a FormGroup or a FormArray) under it's controls property. The top level form in such a case would be the single-source of truth for the form's state, and each step on creation (ngOnInit / constructor) would be able to read data for its respective step from the top level FormGroup. See the pseudocode:
const topLevelFormGroup = new FormGroup({
step1: new FormGroup({fieldForStepOne: new FormControl('')}),
step2: new FormGroup({fieldForStepTwo}),
// ...
});
...
// Step1Component
class Step1Component {
private stepName: string = 'step1';
private formGroup: FormGroup;
constructor(private topLevelFormGroup: any /* DI */) {
this.formGroup = topLevelFormGroup.controls[this.stepName];
}
}
Therefore, the state of the form and each step is kept exactly where it should be—in the form itself!
Why not use session storage? For instance you can use this static helper class (TypeScript):
export class Session {
static set(key:string, value:any) {
window.sessionStorage.setItem(key, JSON.stringify(value));
}
static get(key:string) {
if(Session.has(key)) return JSON.parse(window.sessionStorage[key])
return null;
}
static has(key:string) {
if(window.sessionStorage[key]) return true;
return false;
}
static remove(key:string) {
Session.set(key,JSON.stringify(null)); // this line is only for IE11 (problems with sessionStorage.removeItem)
window.sessionStorage.removeItem(key);
}
}
And using above class, you can put your object with multi-steps-forms data and share it (idea is similar like for 'session helper' in many backend frameworks like e.g. php laravel).
The other approach is to create Singleton service. It can look like that (in very simple from for sake of clarity) (I not test below code, I do it from head):
import { Injectable } from '#angular/core';
#Injectable()
export class SessionService {
_session = {};
set(key:string, value:any) {
this._session[key]= value; // You can also json-ize 'value' here
}
get(key:string) {
return this._session[key]; // optionally de-json-ize here
}
has(key:string) {
if(this.get(key)) return true;
return false;
}
remove(key:string) {
this._session[key]=null;
}
}
And then in your main file where you bootstrap application:
...
return bootstrap(App, [
...
SessionService
])
...
And the last step - critical: When you want to use you singleton service in your component - don't put int in providers section (this is due to angular2 DI behavior - read above link about singleton services). Example below for go from form step 2 to step 3:
import {Component} from '#angular/core';
import {SessionService} from './sessionService.service';
...
#Component({
selector: 'my-form-step-2',
// NO 'providers: [ SessionService ]' due to Angular DI behavior for singletons
template: require('./my-form-step-2.html'),
})
export class MyFormStep2 {
_formData = null;
constructor(private _SessionService: SessionService) {
this._formData = this._SessionService.get('my-form-data')
}
...
submit() {
this._SessionService.set('my-form-data', this._formData)
}
}
It should looks like that.