Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

Angular4入門_Vol.5

参考サイト

https://www.codingforentrepreneurs.com/projects/try-angular-v4/

Safely Embed a Video

  • youtubeのembed(埋め込み)linkを挿入してみる。
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'video-list',
  templateUrl: './video-list.component.html',
  styleUrls: ['./video-list.component.css']
})
export class VideoListComponent implements OnInit {
  title = "Video List!";
  // videoList = ["Item 1", "Item 2", "Item 3"];
  videoList = [
    {
      name: "Item 1",
      slug: "item-1",
      embed: `<iframe width="560" height="315" src="https://www.youtube.com/embed/kzjMI00A1f8" frameborder="0" allowfullscreen></iframe>`
    },
    {
      name: "Item 2",
      slug: "item-2",
      embed: `<iframe width="560" height="315" src="https://www.youtube.com/embed/kzjMI00A1f8" frameborder="0" allowfullscreen></iframe>`
    },
    {
      name: "Item 3",
      slug: "item-3",
      embed: `<iframe width="560" height="315" src="https://www.youtube.com/embed/kzjMI00A1f8" frameborder="0" allowfullscreen></iframe>`
    },
  ]
  constructor() { }

  ngOnInit() {
  }

}
  • video-list.component.html を修正する。
<p>
  {{ title }}
</p>

<p *ngFor='let item of videoList'>
  <a href="videos/{{ item.slug }}" >{{ item.name }}</a>
  {{ item.embed }}
</p>
  • embed linkなはずだが、うまく埋め込まれていない。さらに修正してみる。
<p>
  {{ title }}
</p>

<div *ngFor='let item of videoList'>
  <a href="videos/{{ item.slug }}" >{{ item.name }}</a>
  <div [innerHTML]='item.embed'></div>
  <div [innerHTML]='"<h1>Hi there</h1>"'></div>
</div>
  • これでもembedは機能しない。ので、いろいろと実験してみる。video-listにsomeItemという変数を設定してみる。
export class VideoListComponent implements OnInit {
  title = "Video List!";
  someItem = "<h1>HiHi</h1>";
...
}
<p>
  {{ title }}
</p>

<div *ngFor='let item of videoList'>
  <a href="videos/{{ item.slug }}" >{{ item.name }}</a>
  <div [innerHTML]='item.embed'></div>
  <div [innerHTML]='someItem'></div>
</div>
  • HiHiの方は、htmlが読み込まれた状態で表示される。ただ、埋め込みリンクはうまくいかない。だから、別の方法で、埋め込みリンクを利用してみる。
<p>
  {{ title }}
</p>

<div *ngFor='let item of videoList'>
  <a href="videos/{{ item.slug }}" >{{ item.name }}</a>
  <div [innerHTML]='item.embed'></div>
  <div [innerHTML]='someItem'></div>
  <iframe width="560" height="315" src="https://www.youtube.com/embed/{{ item.embed }}" frameborder="0" allowfullscreen></iframe>
</div>
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'video-list',
  templateUrl: './video-list.component.html',
  styleUrls: ['./video-list.component.css']
})
export class VideoListComponent implements OnInit {
  title = "Video List!";
  someItem = "<h1>HiHi</h1>";
  // videoList = ["Item 1", "Item 2", "Item 3"];
  videoList = [
    {
      name: "Item 1",
      slug: "item-1",
      embed: `kzjMI00A1f8`
    },
    {
      name: "Item 2",
      slug: "item-2",
      embed: `kzjMI00A1f8`
    },
    {
      name: "Item 3",
      slug: "item-3",
      embed: ""
    },
  ]
  constructor() { }

  ngOnInit() {
  }

}
  • これでもうまくいかない、、、なぜだ。errorは、: unsafe value used in a resource URL context (see http://g.co/ng/security#xss)と表示されているので、たぶんこれが問題だろう。srcの部分をng仕様に変更する。また、embed urlも少し加工したurlを渡すため、getEmbedUrlを定義する。
<p>
  {{ title }}
</p>

<div *ngFor='let item of videoList'>
  <a href="videos/{{ item.slug }}" >{{ item.name }}</a>
  <div [innerHTML]='item.embed'></div>
  <div [innerHTML]='someItem'></div>
  <iframe width="560" height="315" [src]="getEmbedUrl()" frameborder="0" allowfullscreen></iframe>
</div>
  • video-list.component.tsに追記する。
getEmbedUrl(){
  return "https://www.youtube.com/embed/{{ item.embed }}";
}
  • これでもだめ!angularのDomSanitizerメソッドをimportして利用してみる。
import { DomSanitizer } from '@angular/platform-browser';
...
constructor(private sanitizer: DomSanitizer) { } // constructorで、sanitizerのアノテーションをDomSanitizerに設定する。
...
getEmbedUrl(){
  return this.sanitizer.bypassSecurityTrustResourceUrl('https://www.youtube.com/embed/{{ item.embed }}');
}
  • これでどうだ。。。表示された!が、うまく動画が再生されない。{{ item.embed }} の部分の挙動がおかしいので、修正する。
getEmbedUrl(item){
  return this.sanitizer.bypassSecurityTrustResourceUrl('https://www.youtube.com/embed/' + item.embed);
}
  • video-list.component.htmlの方も修正する。
<p>
  {{ title }}
</p>

<div *ngFor='let item of videoList'>
  <a href="videos/{{ item.slug }}" >{{ item.name }}</a>
  <div [innerHTML]='item.embed'></div>
  <div [innerHTML]='someItem'></div>
  <iframe width="560" height="315" [src]="getEmbedUrl(item)" frameborder="0" allowfullscreen></iframe>
</div>
  • これで無事表示された!!さらに、item.embedに値が入っている場合のみembedを表示するようにする。
<iframe *ngIf='item.embed' width="560" height="315" [src]="getEmbedUrl(item)" frameborder="0" allowfullscreen></iframe>

まとめ

  • jsonオブジェクトからのリンクの安全を確保するには、[src]を使うと有効かも?
  • *ngIf, [src] などの文脈で、contextを利用する場合は、'' シングルクオテーションで囲むだけでOK。
  • それ以外のhtml内で利用する場合は、{{}}で囲んで利用する。