Почему документ пуст?

** ОБНОВЛЕНО ** решением, которое близко к работе:

Я пытаюсь получить ссылку "Перейти к содержимому", чтобы перейти к первому фокусируемому элементу после "#content-start".

Логин-base.component.ts:

import { Component, OnInit } from '@angular/core';
import { Inject, Injectable } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';

@Component({
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.scss']
})

export class BaseLoginComponent implements OnInit {

    constructor(
        @Inject(DOCUMENT) private document: any
        ) {
    }


    skip() {
        console.log(document);
        console.log(document.querySelector);
        var content = document.querySelector(`#content-start`); // ?? document is null!!
        if (content) {
            var control = content.querySelector('input, button, a');
            console.log(control);
            //if (control) {
            //    control.focus(); // first only
            //}
        }
    };

    ngOnInit() {
        this.document.getElementById('skipLink').onclick = this.skip;
        this.document.getElementById('skipLink').onkeypress = function (e) {
            if (e.keyCode == 13) {
                this.skip();
            }
        }

    }
}

login.component.html:

<div class="login-page">
    <section class="main container" id="content-start">
        <input type="text"/>

Это на самом деле работает, поскольку console.log(control) возвращает

<input _ngcontent-c4="" id="username" name="username">

что на самом деле правильный контроль.

Но я не могу просто установить.focus(), потому что у меня есть фрагмент HTML, а не объект с методами, такими как.focus();

А есть ли угловой эквивалент $(control) в jQuery?

3 ответа

Как вы узнали, skipLink должен быть методом класса вашего компонента. Для того, чтобы поддерживать правильный this Внутри skipLink, вы можете установить обработчики событий с addEventListener и функции стрелок:

public ngOnInit() {
    this.document.getElementById('skipLink').addEventListener("click", () => { 
      this.skipLink(); 
    });
    this.document.getElementById('skipLink').addEventListener("keypress", (e) => {
        if (e.keyCode == 13) {
            this.skipLink();
        }
    }
}

private skipLink() {
    let control: HTMLElement = this.document.querySelector('input, button, a');
    if (control) {
        control.focus();
    }
}

Вы можете увидеть код на работе в этом поршне.


Как упомянул Кевин, используя ViewChild это более стандартный способ ссылки на элемент в компоненте. Вы можете определить ссылочную переменную шаблона на целевом элементе (например, #firstButton в шаблоне компонента ниже), получить ссылку на него с ViewChildи получить сам HTML-элемент с nativeElement имущество. Что касается обработчиков событий, вы можете установить их с угловой привязкой (например, (click)="skipLink()").

Этот метод показан в этом плункере:

import { Component, NgModule, Inject, ElementRef, ViewChild } from '@angular/core';
...

@Component({
    selector: 'my-app',
    template: `
        <button #firstButton>Focusable Button</button>
        <br/>
        <button (click)="skipLink()">Click here to set focus on first button</button>
    `,
    ...
})
export class App {

    @ViewChild("firstButton") private firstButton: ElementRef;

    private skipLink() {
        this.firstButton.nativeElement.focus();
    }
}   

Это происходит потому, что DOM еще не загружен в ngOnInit, Обновите ваш код, чтобы он выглядел так, реализуя AfterViewInit:

export class AppComponent implements AfterViewInit{
constructor(
    @Inject(DOCUMENT) private document: any
) { }
}

ngAfterViewInit() {

    this.document.getElementById('skipLink').onclick = skipLink;
    this.document.getElementById('skipLink').onkeypress = function (e) {
        if (e.keyCode == 13) {
            skipLink();
        }
    }

    function skipLink() {
        let content: HTMLElement = this.document.querySelector("#content-start"); // ?? document is null!!
        if (content) {
            let control: HTMLElement = this.document.querySelector('input, button, a');
            console.log(control);
            if (control) {
                // control.focus(); // first only
            }
        }
    }
}

ngAfterViewInit делает именно так, как это звучит; он запускается только после начальной загрузки представления.

Отредактируйте в ответ на правку вашего вопроса: Вы ищете angular.element. Документация по этому вопросу действительно полезна и является лучшей практикой программирования для манипулирования элементом в Angular.

Это довольно далеко от первоначальной реализации; если я обновлю вступительный пост, комментарии не будут иметь смысла.

Следуя совету Кевина по реализации ViewChild в Angular для доступа к дочернему компоненту, директиве или элементу DOM(если только я не неправильно понял):

import { Component, ViewChild, AfterViewInit, ElementRef   } from '@angular/core';

export class AppComponent {

    @ViewChild('firstControl') firstControl: ElementRef;

    skipLink() {
        console.log(this.firstControl);
        //if (this.firstControl) { this.firstControl.focus(); }
    };

,

<a href="#content-start" id="skipLink" (click)="skipLink()">Skip to main content</a>

К сожалению, это не лучше. this.firstControl не определен.

Другие вопросы по тегам