Встроенный виджет Twitter в приложении Angular 2+ отображается только при загрузке первой страницы

Мое приложение работает отлично, если я копирую именно встроенную функцию из документов Twitter ( https://dev.twitter.com/web/javascript/loading) в функцию ngAfterViewInit, но когда я переключаю маршрут, виджет также исчезает.

Вот код для работы только для первой загрузки страницы:

import { Component, OnInit, OnDestroy, AfterViewInit } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute, ParamMap, Params } from '@angular/router';
import { Observable, Subscription } from 'rxjs/Rx';

export class ProjectDetailComponent implements OnInit, OnDestroy, AfterViewInit {

constructor(
    private route: ActivatedRoute,
    private router: Router
  ) { }

ngOnInit(){}

ngAfterViewInit(){
  (<any>window).twttr = (function(d, s, id) {
      let js, fjs = d.getElementsByTagName(s)[0],
        t = (<any>window).twttr || {};
      if (d.getElementById(id)) return t;
      js = d.createElement(s);
      js.id = id;
      js.src = 'https://platform.twitter.com/widgets.js';
      fjs.parentNode.insertBefore(js, fjs);

      t._e = [];
      t.ready = function(f) {
        t._e.push(f);
      };

      return t;
    }(document, 'script', 'twitter-wjs'));
}

}

Затем я нашел приемлемое решение от этого ( виджет Twitter на Angular 2), но виджет даже не отображается с первой загрузки и никаких ошибок, поэтому я даже не знаю, где я был не прав.

Вот код, который никогда не показывает виджет Twitter без каких-либо ошибок:

import { Component, OnInit, OnDestroy, AfterViewInit } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute, ParamMap, Params } from '@angular/router';
import { Observable, Subscription } from 'rxjs/Rx';

export class ProjectDetailComponent implements OnInit, OnDestroy, AfterViewInit {

private subscription: Subscription;
constructor(
    private route: ActivatedRoute,
    private router: Router
  ) { }

ngOnInit(){}

ngAfterViewInit(){
  this.subscription = this.router.events.subscribe(val => {
  if (val instanceof NavigationEnd) {
    (<any>window).twttr = (function (d, s, id) {
      let js: any, fjs = d.getElementsByTagName(s)[0],
          t = (<any>window).twttr || {};
      if (d.getElementById(id)) return t;
      js = d.createElement(s);
      js.id = id;
      js.src = 'https://platform.twitter.com/widgets.js';
      fjs.parentNode.insertBefore(js, fjs);

      t._e = [];
      t.ready = function (f: any) {
          t._e.push(f);
      };

      return t;
    }(document, 'script', 'twitter-wjs'));

    if ((<any>window).twttr.ready())
      (<any>window).twttr.widgets.load();
  }
});
}

ngOnDestroy() {
  this.subscription.unsubscribe();
}    
}

В основном, я подписываю данные виджета до NavigationEnd затем отписаться в ngOnDestroy, так что я все еще могу сохранить данные между переключателем маршрута. Я считаю, что логика верна, поскольку решение сработало и для кого-то, но для меня оно никогда не работало до этого момента.

3 ответа

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

ngOnInit() {
   (<any>window).twttr.widgets.load();
}

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

Итак, чтобы это исправить, просто поместите код в конструктор (чтобы виджет загружался перед представлением) примерно так:

import { Component, OnDestroy } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';

@Component({ ... })

export class HomeComponent implements OnDestroy {
  private twitter: any;

  constructor(private _router: Router) {
    this.initTwitterWidget();
  }

  initTwitterWidget() {
    this.twitter = this._router.events.subscribe(val => {
      if (val instanceof NavigationEnd) {
        (<any>window).twttr = (function (d, s, id) {
          let js: any, fjs = d.getElementsByTagName(s)[0],
              t = (<any>window).twttr || {};
          if (d.getElementById(id)) return t;
          js = d.createElement(s);
          js.id = id;
          js.src = "https://platform.twitter.com/widgets.js";
          fjs.parentNode.insertBefore(js, fjs);

          t._e = [];
          t.ready = function (f: any) {
              t._e.push(f);
          };

          return t;
        }(document, "script", "twitter-wjs"));

        if ((<any>window).twttr.ready())
          (<any>window).twttr.widgets.load();

      }
    });
  }

  ngOnDestroy() {
    this.twitter.unsubscribe();
  }
}

Если я найду информацию о том, почему предыдущий код был нарушен, я обновлю этот ответ. (Или, если кто-то еще знает, не стесняйтесь редактировать это)

Хорошо, я нашел способ обойти это на основе этой ссылки ( Почему мой твиттер-виджет не будет отображаться, если я изменю представление в angularjs?). Нет необходимости подписки на события, мне нужно обернуть функцию в setTimeOut перерисовать его между переключателем маршрута. Не забудьте также обернуть setTimeOut функция внутри isPlatformBrowser для лучшей практики предварительного рендеринга. Вот код:

import { Component, OnInit, OnDestroy, AfterViewInit, PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

constructor(@Inject(PLATFORM_ID) private platformId: Object) { }

ngAfterViewInit() {    
 if (isPlatformBrowser(this.platformId)) {
  setTimeout(function() { 
    (<any>window).twttr = (function(d, s, id) {
      let js, fjs = d.getElementsByTagName(s)[0],
        t = (<any>window).twttr || {};
      if (d.getElementById(id)) return t;
      js = d.createElement(s);
      js.id = id;
      js.src = 'https://platform.twitter.com/widgets.js';
      fjs.parentNode.insertBefore(js, fjs);

      t._e = [];
      t.ready = function(f) {
        t._e.push(f);
      };

      return t;
    }(document, 'script', 'twitter-wjs'));
    (<any>window).twttr.widgets.load(); }, 100);
  }
}
Другие вопросы по тегам