Вызов метода веб-компонента Angular (CustomElement)

У меня есть два примера:

Пример 1:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})

export class AppComponent {
  options:any = {isOpen: false };

  logOptions() {
    console.log(this.options);
  }

}

Пример 2:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})

export class AppComponent {
  options:any = {isOpen: false };

  @Input() logOptions() {
    console.log(this.options);
  }

}

в html:

<app-root></app-root>

<script>
  document.querySelector('app-root').logOptions();
</script>

В примере 1 возвращается ошибка: document.querySelector(...).logOptions is not a function

В примере 2 возвращается: undefined

У кого-нибудь есть какие-либо идеи?


person ferhado    schedule 08.07.2020    source источник
comment
Чего вы здесь надеетесь достичь? Расскажите нам, что поможет нам указать вам в правильном направлении. Но что касается Example 2, вы получите undefined, потому что вы объявили переменную с именем options в классе, но не присвоили ее ничему, поэтому по умолчанию она будет undefined, когда вы вызываете функцию, которая записывает значение в консоль.   -  person Muirik    schedule 15.07.2020
comment
Я пытаюсь создать настраиваемый элемент, который позже смогу использовать в простом приложении js, например модальном диалоговом окне с методами открытия и закрытия.   -  person ferhado    schedule 15.07.2020
comment
В примере 2 я получаю undefined также, когда определены параметры, я обновил пример выше   -  person ferhado    schedule 15.07.2020
comment
Не уверен, как / где вы пытаетесь получить this.options, но вот пример, в котором я вызываю вашу logOptions() функцию в ловушке жизненного цикла ngOnInit() и не имею проблем с получением значения: stackblitz.com/edit/   -  person Muirik    schedule 15.07.2020
comment
Вы смотрели на stackblitz? Я думаю, вам нужно предоставить больше вашего кода, поскольку неясно, как вы на самом деле вызываете свою функцию в компоненте, если вы не используете что-то вроде ngOnInit().   -  person Muirik    schedule 15.07.2020
comment
Я сделал пример на stackblitz, но это не похоже на то, чтобы работать на stackblitz, попробуйте то же самое на localhost stackblitz.com/edit/angular-web-component-custom-element   -  person ferhado    schedule 15.07.2020
comment
проверьте файлы index.html, app.module, app.compoenet   -  person ferhado    schedule 15.07.2020
comment
Ваш тег script в корневом каталоге приложения запускается первым, при регистрации в консоли вы увидите, что он запускается до вашего конструктора компонента, и даже если вам удастся дождаться разрешения компонента angular, вы все равно не сможете получить доступ к getOptions через DOM. вы пробовали решение на основе событий? вы можете зарегистрировать пользовательские события в своем компоненте angular и запускать их вручную в любом месте, даже в теге script с помощью document.dispatchEvent   -  person Alejandro Camba    schedule 15.07.2020


Ответы (1)


Немного поздно, но если вам это все еще нужно, есть несколько способов заставить его работать.

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html'
})

export class AppComponent {

    // @Input() << see comments below
    options: any = {isOpen: false };
    
    // This will NOT be available outside the component, in plain JS
    logOptions() {
        console.log(this.options);
    }

    // This will work ONLY if options is @Input()
    @Input()
    logOptions2() {
        console.log(this.options);
    }
    
    // This property will always provide correct data
    // Ideally a getter should not be @Input() though
    @Input()
    get logOptions3() {
        return this.options;
    }
}

Вы можете получить к ним доступ в виде простого JavaScript кода как

const logComponentOptions = () => {
    const el = document.querySelector('app-root');
    // el.logOptions(); << Error
    el.logOptions2(); // works ONLY if options is @Input()
    console.log(el.logOptions3); // WORKS
    console.log(el.options); // if options is @Input()
}
  1. Таким образом, свойство logOptions3 всегда можно использовать для получения options из простого javaScript кода. Но семантически неверно (getter как @Input())
  2. Первый logOptions() метод недоступен извне, так как он НЕ помечен @Input()
  3. Метод logOptions2() доступен, но может печатать только правильное значение, ЕСЛИ options также отмечен @Input()
  4. Но если вы пометите свойство options как @Input(), вы можете получить прямой доступ к нему, а не обертывать его другим методом.
  5. Наконец, если вы просто создаете @Input() options = false, вы также можете получить к нему доступ как к простому атрибуту из HTML
<app-root options="false"></app-root>

Обновлять

Если вы хотите передать данные в компонент, вы можете просто предоставить свойство setter с помощью @Input. Затем вы можете установить значение извне компонента с помощью JavaScript

@Input()
public set myData(value: MyDataType) {
    // validation & logic if any
    this._myData = value;
}

// Then in JavaScript
const el = document.querySelector('app-root');
el.myData = {a: 10, b: true, c: 'my data object' }
person Arghya C    schedule 17.07.2020
comment
Спасибо за вашу помощь, но logOptions3 () с set или get в любом случае возвращает ошибку .logOptions3 is not a function, мне нужно вызвать метод и передать некоторые данные компоненту из javascript, эти данные могут быть объектами типа, например: setOptions({isOpen: true}) - person ferhado; 18.07.2020
comment
Обратите внимание, что logOptions3 теперь является свойством (только для чтения, с get), поэтому это НЕ функция. Просто назовите его как свойство el.logOptions3 без скобок ???? Для передачи данных в компонент я обновил свой ответ - person Arghya C; 18.07.2020