1
私は、次のような問題のまわりで私の頭をラップしようとしている:角度2反応型+ディレクティブ検証
私は入力欄にオートコンプリート機能を追加「グーグル・場所・オートコンプリート」ディレクティブを持っています。
Googleプレースを強制的に選択できるようにし、ユーザーがプレースを選択した場合にのみ「有効」になるようにしました。
例えば:私はテンプレート駆動の形でこのディレクティブを使用する場合は
@Directive({
selector: '[googlePlace][formControlName], [googlePlace][ngModel]',
providers: [{provide: NG_VALIDATORS, useExisting: GooglePlaceDirective, multi: true}]
})
export class GooglePlaceDirective implements Validator, OnChanges {
valid = false;
@Output() googlePlaceAddressChange: any = new EventEmitter();
@Input() googlePlaceAddress: any;
@Output() ngModelChange: any = new EventEmitter();
private autocomplete: any;
constructor(private googleMapService: GoogleMapsService,
private element: ElementRef,
private zone: NgZone) {
}
ngOnInit() {
let self = this;
this.googleMapService
.load()
.subscribe(
() => {
this.autocomplete = new google.maps.places.Autocomplete(this.element.nativeElement);
this.autocomplete.addListener('place_changed', function() {
self.placeChanged(this.getPlace());
});
}
);
}
private placeChanged(place) {
this.zone.run(() => {
this.googlePlaceAddress = {
address: this.element.nativeElement.value,
formattedAddress: place.formatted_address,
latitude: place.geometry.location.lat(),
longitude: place.geometry.location.lng()
};
this.valid = true;
this.googlePlaceAddressChange.emit(this.googlePlaceAddress);
this.ngModelChange.emit(this.element.nativeElement.value);
});
}
ngOnChanges(changes): void {
let googlePlaceDefined = typeof (changes.googlePlaceAddress) !== 'undefined';
let modelDefined = typeof (changes.ngModel) !== 'undefined';
if(modelDefined && !googlePlaceDefined) {
this.valid = false;
} else if(googlePlaceDefined && !modelDefined) {
this.valid = true;
}
}
validate(control: AbstractControl) {
return this.valid === false ? {'googlePlaceAddress': true} : null;
}
}
:
...
<input name="addr" type="text" [(ngModel)]="textValue" [(googlePlaceAddress)]="googleAddress" required>
<p *ngIf="addr.errors.googlePlaceAddress">Please select a proposed address</p>
...
それが正常に動作します。
今、私はFormGroup
let groups = [
new FormControl('', [Validators.required])
];
/** HTML **/
...
<input [id]="addr"
[formControlName]="address"
class="form-control"
type="text"
googlePlace
[placeholder]="question.label"
[(googlePlaceAddress)]="googleAddress">
...
を用いた反応性フォームでこれを使用する必要がある。しかし、この場合、指令からの検証がトリガされることはありません。
私はangular2は、反応性フォームを使用している場合、それは、経由与えられることを期待しているとします
new FormControl('', [Validators.required, ???])
私はどこか間違った道をとっている必要があります。私は価値のアクセサと一緒に外のコンポーネントを作成する私の問題解決
::私はValidators.requiredとFormGroupでそれを使用することができ、これを使用して@Component({
selector: 'app-google-place',
templateUrl: './google-place.component.html',
styleUrls: ['./google-place.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => GooglePlaceComponent),
multi: true
}
]
})
export class GooglePlaceComponent implements OnInit, ControlValueAccessor {
@ViewChild('inputElement') inputElement: ElementRef;
@Input() public placeholder: string = "Address";
@Input() public textValue: string = "";
private autocomplete: any;
private _place = null;
constructor(
private googleMapService: GoogleMapsService,
private zone: NgZone
) {
}
ngOnInit() {
this.googleMapService
.load()
.subscribe(
() => {
this.autocomplete = new google.maps.places.Autocomplete(this.inputElement.nativeElement);
this.autocomplete.addListener('place_changed',() => this.placeChanged());
}
);
}
placeChanged() {
this.zone.run(() => {
let place = this.autocomplete.getPlace();
this._place = {
address: this.inputElement.nativeElement.value,
formattedAddress: place.formatted_address,
latitude: place.geometry.location.lat(),
longitude: place.geometry.location.lng()
};
this.propagateChange(this._place);
});
}
onNgModelChange($event) {
if(this._place !== null) {
if(this._place.address !== $event) {
this._place = null;
this.propagateChange(this._place);
}
}
}
onBlur() {
this.propagateTouched();
}
writeValue(obj: any): void {
if(obj !== undefined) {
this._place = obj;
}
}
propagateChange = (_: any) => {};
registerOnChange(fn) {
this.propagateChange = fn;
}
propagateTouched =() => {};
registerOnTouched(fn: any): void {
this.propagateTouched = fn;
}
}
をし、今後の参考のため
非常に興味深い、私はあなたと同じことをしたいと思います。あなたは 'GoogleMapsService'とそれを入力にどのようにバインドするのかを表示できますか? –
編集内容にサービスを追加しました – RVandersteen