【问题标题】:Focus input after going to the next step in MatStepper在 MatStepper 中进行下一步后的焦点输入
【发布时间】:2018-02-27 15:00:10
【问题描述】:
【问题讨论】:
标签:
angular
angular-material2
【解决方案1】:
您使用选择更改事件走在正确的道路上。
查看分叉的 StackBlitz:
StackBlitz
您要做的是为您的输入元素分配一个id,这些元素可以与步进器的选定索引相关联,例如:
<mat-step [stepControl]="firstFormGroup">
<form [formGroup]="firstFormGroup">
<ng-template matStepLabel>Fill out your name</ng-template>
<mat-form-field>
<input id="input0" matInput placeholder="Last name, First name" formControlName="firstCtrl" required>
</mat-form-field>
<div>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step [stepControl]="secondFormGroup">
<form [formGroup]="secondFormGroup">
<ng-template matStepLabel>Fill out your address</ng-template>
<mat-form-field>
<input id="input1" matInput placeholder="Address" formControlName="secondCtrl" required>
</mat-form-field>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
然后通过使用选择(selectionChange)事件,您可以在等待输入元素显示在DOM中后将焦点设置在输入元素上:
export class StepperOverviewExample implements AfterViewInit {
isLinear = false;
firstFormGroup: FormGroup;
secondFormGroup: FormGroup;
public targetInput = 'input0';
constructor(private _formBuilder: FormBuilder) { }
ngOnInit() {
this.firstFormGroup = this._formBuilder.group({
firstCtrl: ['', Validators.required]
});
this.secondFormGroup = this._formBuilder.group({
secondCtrl: ['', Validators.required]
});
}
ngAfterViewInit() {
this.setFocus();
}
private setFocus() {
let targetElem = document.getElementById(this.targetInput);
setTimeout(function waitTargetElem() {
if (document.body.contains(targetElem)) {
targetElem.focus();
} else {
setTimeout(waitTargetElem, 100);
}
}, 100);
}
onChange(event: any) {
let index = String(event.selectedIndex);
this.targetInput = 'input' + index;
this.setFocus();
}
}
【解决方案2】:
我已经创建了自己的替代版本,以替代 Narm 提出的版本。我遇到的问题是实际步进器的渲染被推迟(例如从服务器加载数据)ngAfterViewInit 触发得太快了。为了解决这个问题,我在步进动画完成后设置焦点。它会产生轻微的延迟,但允许组件稳定下来。 StackBlitz 和代码:
export class StepperOverviewExample implements OnInit {
isLinear = false;
firstFormGroup: FormGroup;
secondFormGroup: FormGroup;
private targetId = 'input0';
constructor(private _formBuilder: FormBuilder) {}
ngOnInit() {
this.firstFormGroup = this._formBuilder.group({
firstCtrl: ['', Validators.required]
});
this.secondFormGroup = this._formBuilder.group({
secondCtrl: ['', Validators.required]
});
}
setFocus() {
const targetElem = document.getElementById(this.targetId);
targetElem.focus();
}
setTargetId(event: any) {
this.targetId = `input${event.selectedIndex}`;
}
}
<mat-horizontal-stepper (animationDone)="setFocus()" (selectionChange)="setTargetId($event)" [linear]="isLinear" #stepper>
<mat-step [stepControl]="firstFormGroup">
<form [formGroup]="firstFormGroup">
<ng-template matStepLabel>Fill out your name</ng-template>
<mat-form-field>
<input id="input0" matInput placeholder="Last name, First name" formControlName="firstCtrl" required>
</mat-form-field>
<div>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step [stepControl]="secondFormGroup">
<form [formGroup]="secondFormGroup">
<ng-template matStepLabel>Fill out your address</ng-template>
<mat-form-field>
<input id="input1" matInput placeholder="Address" formControlName="secondCtrl" required>
</mat-form-field>
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button matStepperNext>Next</button>
</div>
</form>
</mat-step>
<mat-step>
<ng-template matStepLabel>Done</ng-template>
You are now done.
<div>
<button mat-button matStepperPrevious>Back</button>
<button mat-button (click)="stepper.reset()">Reset</button>
</div>
</mat-step>
</mat-horizontal-stepper>
我认为为了服务器端渲染兼容性,摆脱 document 仍然会很好。
【解决方案3】:
具有输入 ID 和 selectionChange 侦听器的解决方案有效,您还可以添加 (animationDone) 侦听器,这样您就可以在没有 setTimeout() 逻辑的情况下调用 setFocus()。