Передача внешнего атрибута или ввода в пользовательский элемент Angular

#angular #typescript #video.js #custom-component #custom-element

#angular #typescript #video.js #пользовательский компонент #пользовательский элемент

Вопрос:

Я пытаюсь передать ввод объекта в тег пользовательского элемента angular. Пользовательский элемент состоит из тега videojs. Элемент не считывает входные данные, которые я даю в теге пользовательского элемента.

Этот код здесь — мой компонент видеопроигрывателя, который я хочу преобразовать в пользовательский элемент.

 import { Component, ElementRef, Input, On Destroy, OnInit, ViewChild,AfterViewInit, ViewEncapsulation } from '@angular/core';
import videojs from "video.js"

@Component({
  selector: 'app-video-player',
  templateUrl: './my-video-player.component.html',
  styleUrls: ['./my-video-player.component.scss'],
  encapsulation:ViewEncapsulation.Emulated
})
export class MyVideoPlayerComponent implements OnInit,OnDestroy,AfterViewInit {
  @ViewChild('myVideoPlayer',{static:true})
  myVideoPlayer:ElementRef


  @Input() options:{
    fluid:boolean,
    aspectRatio:string,
    autoplay:boolean,
    controls:boolean,
    // height:number,
    // width:number,
    sources:{
      src:string,
      type:string
    }[],
  }

  player:videojs.Player;

  constructor(
  ) { }

  ngAfterViewInit(){
  }
  
  ngOnInit() {
    this.player = videojs(this.myVideoPlayer.nativeElement, this.options, function onPlayerReady() {
      console.log('onPlayerReady', this);
    });    
  }

  ngOnDestroy() {
    
  }

}


 

Вот HTML-код для компонента видеопроигрывателя

 
<video id="video-js" preload="none" class="video-js vjs-default-skin" controls #myVideoPlayer></video>


 

Вот код AppModule, в котором я преобразовал компонент myvideoplayer в пользовательский элемент.

 import { BrowserModule } from '@angular/platform-browser';
import { CUSTOM_ELEMENTS_SCHEMA, DoBootstrap, Injector, NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { MyVideoPlayerComponent } from './my-video-player/my-video-player.component';
import { createCustomElement } from '@angular/elements';

@NgModule({
  declarations: [
    MyVideoPlayerComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
  ],
  providers: [],
  schemas:[CUSTOM_ELEMENTS_SCHEMA],
  bootstrap: [AppComponent],
  entryComponents:[MyVideoPlayerComponent]
})

export class AppModule implements DoBootstrap {
  constructor(private injector:Injector){

    const webComponent=createCustomElement(MyVideoPlayerComponent,{injector:this.injector});
    
    customElements.define('custom-player',webComponent)

  }

  

  ngDoBootstrap(){}
 }


 

После сборки проекта или даже если я напрямую использую внутренний компонент тестирования, который я создал в том же проекте angular. Он показывает компонент видеопроигрывателя, но не воспроизводит видео, поскольку он не может прочитать источник, даже когда я предоставляю атрибуты.

Приведенный ниже код показывает, как я пытаюсь ввести ввод в пользовательский элемент.

 <custom-player options="{ autoplay: true, controls: true, sources: [{ src: '../../assets/video.mp4', type: 'video/mp4' }]}" ></custom-player>


 

Будет полезно, если вы изучите эту проблему.

Вот данный снимок экрана пользовательского элемента, который я объявляю.

Красная метка показывает, что он собирает src, в то время как выделенный маркер показывает, что он не помещает src внутри тега video.

введите описание изображения здесь

Ответ №1:

Вам не нужно ../../ начинать с ресурсов (обычно это допустимая отправная точка из конфигураций).

Кроме того, вы хотите изменить <custom-player options= на <custom-player [options]= (без [] вы фактически передаете строку, а не объект).

Я полагаю, вы следовали какому-то руководству, подобному этому. Если приведенное выше не имеет никакого эффекта, попробуйте сравнить с этим примером, чтобы увидеть, есть ли другие важные различия.

Редактировать:
Очень простой пример привязки свойств:

 // interface for options

export interface VideoOptions {
  fluid?: boolean;
  aspectRation?: string;
  autoplay?: boolean;
  controls?: boolean;
  sources?: Sources[];
}

export interface Source {
  src: string;
  type: string;
}

// ParentComponent ts

export class ParentComponent {
  options: VideoOptions = {
    autoplay: true, 
    controls: true, 
    sources: [{ src: 'assets/video.mp4', type: 'video/mp4' }]
  }
}

// ParentComponent html

<app-child-component [options]="options">
</app-child-component>

// ChildComponent ts
export class ChildComponent {
  @Input() options: VideoOptions;
}

// ChildComponent html
<div>
  {{options?.fluid}} <br>
  {{options?.aspectRatio}} <br>
  {{options?.controls}} <br>
  {{options?.autoplay}} <br>
  <ng-container *ngIf="options.sources">
    <div *ngFor="let source of options.sources">
      {{source.src}} --- {{source.type}}
    </div>
  </ng-container>
</div>
 

Комментарии:

1. <custom-player> на самом деле это, по сути, пользовательский веб-компонент. Является ли мой метод создания компонента правильным? И я читал в некоторых местах, что в пользовательском компоненте вам не нужно использовать [] .

2. [prop]='someVal' (привязка свойств) — это общий механизм angular для привязки значения к свойству в компоненте, на который ссылается шаблон. Я бы рекомендовал вам переместить весь объект options-object из html в переменную в файле ts и передать ее в свой компонент, кстати. (html должен быть как можно более чистым). Помимо этого, этот механизм не имеет ничего общего с тем, используете ли вы свой собственный или какой-либо импортированный / собственный компонент. Добавленная мной ссылка на самом деле делает именно то, что вы делаете (с пользовательским компонентом проигрывателя, обертывающим тег video) и использует [] .

3. Теперь все в порядке. Я нашел причину, по которой мой пользовательский видеопроигрыватель фактически не получал источник для видео, а также остальные элементы управления. Я использую Videojs в angular внутри пользовательского компонента. VideoJS принимает объект в качестве параметров ` <app-my-video-player [options]=»{автозапуск: true, элементы управления: true, источники: [{ src: ‘../../assets/video.mp4’, тип: ‘video/mp4’ }]}»></app-my-video-player> ` Как это указано выше. Но когда я передаю один и тот же объект через атрибуты пользовательского компонента, он преобразует его в строку, а не в объект.

4. <custom-player my-source="{autoplay: true, controls: false, sources: [{ src: './video.mp4', type: 'video/mp4' }]}"></custom-player> вот мой пользовательский компонент, в котором атрибут my-source должен быть отправлен как объект, но он вводится в виде строки, из-за чего проигрыватель videojs не читает его должным образом.

5. Решаемая. Мне просто нужно было преобразовать строку. Сначала я преобразовал строку с помощью JSON. Stringfy. Затем я дважды преобразовал его обратно в JSON.parse и, следовательно, получил желаемый результат. Хотя это был не очень обычный метод, и я уверен, что у людей могут быть лучшие решения. Но на данный момент это сработало для меня. Спасибо 🙂

Ответ №2:

Похоже, вы уже разобрались с этим в своих комментариях, но просто чтобы было понятно всем, кто сталкивается здесь с той же проблемой, вот почему это происходит.

При преобразовании компонента в веб-компонент Angular все входные данные будут сопоставлены, как описано здесь:

https://angular.io/guide/elements#mapping

Пользовательский элемент содержит компонент Angular, обеспечивающий связь между данными и логикой, определенными в компоненте, и стандартными API-интерфейсами DOM. Свойства компонента и логика отображаются непосредственно в атрибутах HTML и системе событий браузера.

API создания анализирует компонент в поисках входных свойств и определяет соответствующие атрибуты для пользовательского элемента. Он преобразует имена свойств, чтобы сделать их совместимыми с пользовательскими элементами, которые не распознают различия в регистре. В результирующих именах атрибутов используются строчные буквы, разделенные тире. Например, для компонента с @Input(‘myInputProp’) inputProp соответствующий пользовательский элемент определяет атрибут my-input-prop.

Пользовательский элемент просто содержит Angular, он сам не является компонентом Angular. Чтобы передать данные на вход, вы должны использовать атрибут, который Angular создает для этого элемента, аналогично тому, как вы используете атрибут данных. Значение атрибута представляет собой строку, поэтому вам нужно преобразовать его в и из JSON, если вы хотите передать объект.