Pracuję z aplikacją front-end z Angular 5 i muszę mieć ukryte pole wyszukiwania, ale po kliknięciu przycisku pole wyszukiwania powinno być wyświetlane i wyostrzone.
Wypróbowałem kilka sposobów znalezionych w StackOverflow z dyrektywą lub tak, ale nie mogę się powieść.
Oto przykładowy kod:
@Component({
selector: 'my-app',
template: `
<div>
<h2>Hello</h2>
</div>
<button (click) ="showSearch()">Show Search</button>
<p></p>
<form>
<div >
<input *ngIf="show" #search type="text" />
</div>
</form>
`,
})
export class App implements AfterViewInit {
@ViewChild('search') searchElement: ElementRef;
show: false;
name:string;
constructor() {
}
showSearch(){
this.show = !this.show;
this.searchElement.nativeElement.focus();
alert("focus");
}
ngAfterViewInit() {
this.firstNameElement.nativeElement.focus();
}
Pole wyszukiwania nie jest aktywne.
Jak mogę to zrobić?
setTimeout(() => { this.searchElement.nativeElement.focus() }, 100)
Powinieneś użyć do tego autofokusa html :
Uwaga: jeśli twój komponent jest utrwalony i ponownie użyty, będzie automatycznie ustawiał ostrość tylko przy pierwszym dołączeniu fragmentu. Można temu zaradzić, mając globalny odbiornik domeny, który sprawdza atrybut autofocus wewnątrz fragmentu dom, gdy jest on dołączony, a następnie ponownie go stosuje lub aktywuje za pomocą javascript.
źródło
Ta dyrektywa natychmiast skupi się i zaznaczy dowolny tekst w elemencie, gdy tylko zostanie wyświetlony. W niektórych przypadkach może to wymagać setTimeout, nie zostało to zbytnio przetestowane.
A w HTML:
źródło
Mam zamiar rozważyć to (rozwiązanie Angular 7)
import {AfterViewInit, Directive, ElementRef, Input,} from '@angular/core'; @Directive({ selector: 'input[appFocus]', }) export class FocusDirective implements AfterViewInit { @Input('appFocus') private focused: boolean = false; constructor(public element: ElementRef<HTMLElement>) { } ngAfterViewInit(): void { // ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. if (this.focused) { setTimeout(() => this.element.nativeElement.focus(), 0); } } }
źródło
To działa i Angular 8 bez setTimeout:
Wyjaśnienie: OK, więc to działa z powodu: Wykrywania zmian. To ten sam powód, dla którego działa setTimout, ale po uruchomieniu setTimeout w Angular ominie Zone.js i uruchomi wszystkie sprawdzenia ponownie, i działa, ponieważ po zakończeniu setTimeout wszystkie zmiany są zakończone. Przy prawidłowym haku cyklu życia (AfterContentChecked) można osiągnąć ten sam wynik, ale z tą zaletą, że dodatkowy cykl nie zostanie uruchomiony. Funkcja zostanie uruchomiona, gdy wszystkie zmiany zostaną sprawdzone i przekazane, i zostanie uruchomiona po zaczepach AfterContentInit i DoCheck. Jeśli się mylę, popraw mnie.
Więcej cykli życia i wykrywanie zmian na https://angular.io/guide/lifecycle-hooks
AKTUALIZACJA : Znalazłem jeszcze lepszy sposób, aby to zrobić, jeśli używa się Angular Material CDK, pakietu a11y. Najpierw zaimportuj A11yModule do modułu deklarując komponent, w którym masz pole wejściowe. Następnie użyj dyrektyw cdkTrapFocus i cdkTrapFocusAutoCapture i użyj w ten sposób w html i ustaw tabIndex na wejściu:
Mieliśmy pewne problemy z naszymi listami rozwijanymi dotyczącymi pozycjonowania i responsywności i zamiast tego zaczęliśmy używać OverlayModule z cdk, a ta metoda wykorzystująca A11yModule działa bez zarzutu.
źródło
cdkTrapFocusAutoCapture
atrybutu, ale zmieniłem Twój pierwszy przykład na mój kod. Z nieznanych (dla mnie) powodów nie działał z zaczepem cyklu życia AfterContentChecked, ale tylko z OnInit. W szczególności z AfterContentChecked nie mogę zmienić fokusa i przenieść (za pomocą myszy lub klawiatury) na inne wejście bez tej dyrektywy w tej samej formie.W Angular, w samym HTML, możesz ustawić fokus na wprowadzanie po kliknięciu przycisku.
źródło
mat-select
selectionChanged
wydarzenia, które ma miejsce przed innymi elementami interfejsu użytkownika, więc przyciągnięcie uwagi w tym momencie nie zadziałało. Zamiast tego musiałem napisać metodęsetFocus(el:HTMLElement):void { setTimeout(()=>el.focus(),0); }
i wywołać ją z obsługi zdarzeń:<mat-select (selectionChanged)="setFocus(myInput)">
. Nie tak ładne, ale proste i działa dobrze. dzięki!Aby wykonać wykonanie po zmianie wartości logicznej i uniknąć wykorzystania limitu czasu, możesz wykonać:
źródło
Istnieje również atrybut DOM o nazwie,
cdkFocusInitial
który działa dla mnie na wejściach. Możesz przeczytać więcej na ten temat tutaj: https://material.angular.io/cdk/a11y/overviewźródło
Tylko przy użyciu szablonu kątowego
źródło
html komponentu:
<input [cdkTrapFocusAutoCapture]="show" [cdkTrapFocus]="show">
kontroler komponentu:
showSearch() { this.show = !this.show; }
.. i nie zapomnij o imporcie A11yModule z @ angular / cdk / a11y
import { A11yModule } from '@angular/cdk/a11y'
źródło
Mam ten sam scenariusz, to zadziałało dla mnie, ale nie mam funkcji „ukryj / pokaż”, którą masz. Więc może mógłbyś najpierw sprawdzić, czy skupiasz się, gdy masz zawsze widoczne pole, a następnie spróbować rozwiązać, dlaczego nie działa, gdy zmienisz widoczność (prawdopodobnie dlatego musisz zastosować sen lub obietnicę)
Aby ustawić fokus, to jedyna zmiana, którą musisz zrobić:
Twoje dane wejściowe HTML powinny wyglądać następująco:
w swojej klasie TS, odwołaj się w ten sposób w sekcji zmiennych (
Twój przycisk jest w porządku, dzwonię:
i to wszystko. Możesz sprawdzić to rozwiązanie w tym poście, które znalazłem, a więc dzięki -> https://codeburst.io/focusing-on-form-elements-the-angular-way-e9a78725c04f
źródło
Łatwiej też jest to zrobić.
źródło