2

I created a Twitter widget and I'm trying to put it in my Angular 2 project, but the JS file does not work.

If I insert it with JS (Here) it works, but when I switch to another tab and back (I have Angular Routing installed) it disappears and shows whatever is in A tag (so, "Tweets by ...").

HTML code (it's in home component):

<md-card-content>
  <a class="twitter-timeline" data-lang="en" data-height="350" data-theme="light" data-chrome="noborders nofooter noheader noscrollbar transparent" href="https://twitter.com/profile">Tweets by profile</a>
</md-card-content>

Script in home.component.ts, the code was provided by @Arg0n (look in answers section):

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

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  constructor(private _router : Router) { }

  public ngOnInit() {
    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"));
        twttr.widgets.load();
      }
    })
  }

}

EDIT: Alright, I did some research and found out that I have to load the widget again with twttr.widgets.load(); but doing that, it throws me an error.

I edited the code above, so you can see what I've tried. The code above returns an error:

[ts] Cannot find name 'twttr'

if I append (window). to it, it throws me this:

EXCEPTION: Uncaught (in promise): TypeError: Cannot read property 'load' of undefined

The documentation on load property is here: https://dev.twitter.com/web/javascript/initialization

GTX
  • 727
  • 2
  • 13
  • 30
  • You should provide more informations, how are we suppose to know how to solve your problem, if we don't know the code? – Haseoh Mar 24 '17 at 07:38
  • Done, anything else you need? – GTX Mar 24 '17 at 07:43
  • The script inserted by twitter probably doesn't run when you switch views in angular. Try using a router event to kick it off again. – Arg0n Mar 24 '17 at 07:58

3 Answers3

7

Alright, I found a solution to this. When we switch between Angular routers, the widget unloads. That's why we put a subscriber, so we load the widget every time we switch between tabs. We can see here how to load the widget for lazy-loading content. When the page is ready, we can use that function to load the widget. Don't forget to unsubscribe after the view is destroyed!

Code:

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();
  }
}
GTX
  • 727
  • 2
  • 13
  • 30
  • I found removing the Router \ NavigationEnd event listeners, and instead just using ngAfterViewInit worked a little better for me, as the NavigationEnd event doesn't fire when reloading the browser at the same path. Thanks for the solution though, helped me loads! – Richard Dunn Jul 14 '18 at 13:06
2

Example for my comment (relevant parts):

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

@Component({ ... })
export class MyComponent implements OnInit {
  constructor(private _router: Router) {}

  public ngOnInit() {
    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"));
      }
    });
  }
}
Arg0n
  • 8,283
  • 2
  • 21
  • 38
  • It doesn't work, it doesn't show tweets when I switch between pages. – GTX Mar 24 '17 at 15:08
  • Okay, this is just a 'maybe' answer to be honest. Can't test this. Do you get any errors in console? Can you debug and set a breakpoint to see what happens? – Arg0n Mar 24 '17 at 15:09
  • Well, I get this error: https://syndication.twitter.com/i/jot/syndication?l=%7B%22_category_%22%3A%…w%22%2C%22page%22%3A%22timeline%22%2C%22action%22%3A%22impression%22%7D%7D Failed to load resource: the server responded with a status of 400 () but I'm not sure if it's because of your code. I'm gonna debug now. – GTX Mar 24 '17 at 15:12
  • Okay, the script doesn't run when I switch tabs. – GTX Mar 24 '17 at 15:15
  • You never get inside the `this._router.events.subscribe(val => { ... });` function? – Arg0n Mar 24 '17 at 15:16
  • Only when I (re)load the whole page. – GTX Mar 24 '17 at 15:17
  • Then it sounds as if you're on the same route even when changing tabs. Maybe you have another event, or your own 'clickOnTab' event you can hook up to? – Arg0n Mar 24 '17 at 15:17
  • Well, what's weird is: it doesn't go past "val instanceof NavigationEnd", it triggers fine if I log something before that statement, but it logs it three times. – GTX Mar 24 '17 at 15:27
  • Then maybe you have another version than me. Try to see which event is the last of them (the third), and replace `NavigationEnd` with that. – Arg0n Mar 24 '17 at 15:29
  • Sorry, I tried to put the `console.log` right after the instanceof statement and it works (it even triggers multiple times), but it won't go past `if (d.getElementById(id)) return t;`, so I guess that's intended, but it's still not working. – GTX Mar 24 '17 at 15:37
  • Try changing that line to: `if (d.getElementById(id)) d.getElementById(id).remove();`. If that gets you nowhere i'm at a loss without having any code/fiddle to look at. – Arg0n Mar 24 '17 at 15:48
1

This will work for me on angular 7.2.2 and ionic 4.1. angular can build and ionic can build app and test on cordova.

solution from : embedded Twitter widget on Angular 2+ app only shows up on the first page load

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);
  }
}

put here in .ts and put twitter tag in template files

barbsan
  • 3,418
  • 11
  • 21
  • 28
a0fzide
  • 11
  • 1