I have go through with following questions but didn't found any solution.
I have made a custom validation directive to validate unique permalink. this code working fine but when i try to create a build for production then it gives me following error:-
ERROR in : Can't resolve all parameters for UniquePermalinkValidatorDirective in E:/Manish/Projects/ampleAdmin/src/app/shared/permalink-validation.directive.ts: ([object Object], ?).
permalink-validation.directive.ts
import { Directive } from '@angular/core';
import { AsyncValidator, AbstractControl, ValidationErrors, NG_ASYNC_VALIDATORS, AsyncValidatorFn } from '@angular/forms';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
import * as qs from 'qs';
import { PageService } from '../services/page.service';
import { IPage } from '../client-schema';
export function UniquePermalinkValidator(pageService: PageService, page: IPage): AsyncValidatorFn {
return (ctrl: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> => {
if (!(ctrl && ctrl.value)) { return null; }
const cond: any = {
where: {
permalink: ctrl.value
}
};
if (page && page.id) {
cond.where.id = { nin: [page.id]};
}
const query = qs.stringify(cond, { addQueryPrefix: true });
return pageService.getPageCount(query).pipe(
map(res => {
return res && res.count ? { uniquePermalink: true } : null;
})
);
};
}
@Directive({
selector: '[appUniquePermalink]',
providers: [{ provide: NG_ASYNC_VALIDATORS, useExisting: UniquePermalinkValidatorDirective, multi: true }]
})
export class UniquePermalinkValidatorDirective implements AsyncValidator {
constructor(private pageService: PageService, private page: IPage) { }
validate(ctrl: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
return UniquePermalinkValidator(this.pageService, this.page)(ctrl);
}
}
page.component.ts
import { Component, OnInit, TemplateRef } from '@angular/core';
import * as _ from 'lodash';
import { NotifierService } from 'angular-notifier';
import { BsModalService, BsModalRef } from 'ngx-bootstrap/modal';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { IPage } from 'src/app/client-schema';
import { Utils } from 'src/app/shared/utils';
import { PageService } from 'src/app/services/page.service';
import { UniquePermalinkValidator } from 'src/app/shared/permalink-validation.directive';
@Component({
selector: 'app-page',
templateUrl: './page.component.html',
styleUrls: ['./page.component.css']
})
export class PageComponent implements OnInit {
private notifier: NotifierService;
pageForm: FormGroup;
pageDetail: IPage;
isAddFold = false;
isEditFold = false;
editFoldIndex = -1;
constructor(
private pageService: PageService,
private notifierService: NotifierService,
private modalService: BsModalService,
private formBuilder: FormBuilder,
) {
this.notifier = notifierService;
}
initPageForm() {
this.pageForm = this.formBuilder.group({
name: ['', [Validators.required, Validators.minLength(2), Validators.maxLength(250)]],
permalink: ['', [Validators.required], UniquePermalinkValidator(this.pageService, this.pageDetail)],
folds: [
[]
],
data: null,
status: true
});
}
}
I am using single form for Add/Edit page so i have to require records details to allow permalink on editing a page.
is there any way to pass current page details to directive?
Given
export function UniquePermalinkValidator(pageService: PageService, page: IPage): AsyncValidatorFn {
// ...
}
And given
@Directive({
selector: '[appUniquePermalink]',
providers: [{ provide: NG_ASYNC_VALIDATORS, useExisting: UniquePermalinkValidatorDirective, multi: true }]
})
export class UniquePermalinkValidatorDirective implements AsyncValidator {
constructor(private pageService: PageService, private page: IPage) {}
// ...
}
And given that IPage
is defined solely by
export interface IPage {
id: number;
// ...
}
Then UniquePermalinkValidatorDirective
will not work by definition, failing in the manner described.
An interface
defines something only in the type space, not in the value space and therefore has no runtime manifestation whatsoever. This means it cannot be used in a value position.
In essence, Angular's dependency injection system reads the type of constructor parameters and, when there is a correspondingly named declaration in the value space, it will use that correspondingly named value as the injection token.
For example, the following
import {Injectable} from '@angular/core';
@Injectable() export class Service {
constructor(http: Http) {}
}
can also be written
import {Inject} from '@angular/core';
export class Service {
constructor(@Inject(Http) http: ThisTypeIsArbitraryWithRespectToInjection) {}
}
which means the same thing
Notice how Http
is pass as an argument to Inject
. But Inject(IPage)
, where IPage
is an interface
, is malformed.
A primary purpose of @Inject(ProviderToken)
is to allow one to inject a provider orthogonally to the type of the decorated paramater in cases such as yours.
Therefore, you need something like
constructor(@Inject(pageToken) page) {}
Which means one needs to define a token and use it to register a provider that can be injected.
One can, and should, still write
constructor(@Inject(pageToken) page: IPage) {}
In order to give the parameter a type but the type is unrelated to the value injected for the parameter.
For example
import {InjectionToken, NgModule} from '@angular/core';
export const pageToken = new InjectionToken<IPage>('Page');
@NgModule({
providers: [
{
provide: pageToken,
useFactory: functionReturningAPage
}
]
}) export class // ...