Search code examples
twitterinstagramionic4

Embedded tweets and instagram posts are viewed only once in ionic 4?


It seems that the scripts that are responsible for rendering the Instagram and Twitter blockquotes are running only once.

When navigating to another page containing Twitter or Instagram blockquotes the embedded iframe is viewed correctly, but when navigating to the same page, the blockquotes are NOT rendered!

This is how I had included the corresponding scripts:

  twitterPosts = function (d, s, id) {
    let js: any,
      fjs = d.getElementsByTagName(s)[0],
      p = 'https';

    if (!d.getElementById(id)) {
    js = d.createElement(s);
    js.id = id;
    js.src = p + "://platform.twitter.com/widgets.js";
    fjs.parentNode.insertBefore(js, fjs);
     }
  }(document, "script", "twitter-wjs");

  instagramPosts = function (d, s, id) {
    let js: any;
    let fjs = d.getElementsByTagName(s)[0];

    if (!d.getElementById(id)) {
    js = d.createElement(s);
    js.setAttribute("onLoad", "window.instgrm.Embeds.process()");
    js.id = id;
    js.src = "https://platform.instagram.com/en_US/embeds.js";

    fjs.parentNode.insertBefore(js, fjs);
    }
  }(document, "script", "instagram-wjs");

 ionViewWillEnter() {
    ...
    this.instagramPosts;
    this.twitterPosts;
...
}

ionViewWillLeave() {
    this.removeScript();
  }

removeScript() {
    let fjs = document.getElementsByTagName('script')[0];
    fjs.parentElement.removeChild(document.getElementById('instagram-wjs'));
  }

I also had tried to run these scripts after adding the HTML content containing the blockquotes:

this.htmlContent = this.domSanitizer.bypassSecurityTrustHtml(this.post.content);

this.instagramPosts;
this.twitterPosts;

How can I lmake the scripts always render the blockquotes?!


Solution

  • The Twitter and Instagram embeds are rendered by the functions twttr.widgets.load() and instgrm.Embeds.process() respectively, where these functions are fired on the "onload" event of the scripts that are responsible for embedding Twitter and Instagram.

    I had noticed that when navigating to the same page in ionic, the page's source code is not re-rendered as it is clear from inspecting in the browser.

    I had tried calling the (<any>window)twttr.widgets.load() and (<any>window)instgrm.Embeds.process() functions in the ionViewWillEnter(), ionViewDidEnter(), and ngAfterViewInit() but resulting with the error "cannot read property widgets of undefined"!

    Finally, I had found the solution!

    Someone had proposed a solution for Twitter embeds in Angular, and it worked in ionic! https://stackoverflow.com/a/43048814/10533962

    The solution is to save the instance of Twitter widget to the (<any>window) object, in order to be able to call the function belonging to it again.

    I had applied the same logic on the Instagram embeds and it worked!

    This is my final code:

      twitterRender() {
        (<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();
      }
    
      instagramRender() {
        (<any>window).instagram = function (d, s, id) {
          let js: any;
          let fjs = d.getElementsByTagName(s)[0],
            i = (<any>window).instagram || {};
    
          if (!d.getElementById(id)) {
            js = d.createElement(s);
            js.setAttribute("onLoad", "window.instgrm.Embeds.process()");
            js.id = id;
            js.src = "https://platform.instagram.com/en_US/embeds.js";
    
            fjs.parentNode.insertBefore(js, fjs);
    
            i._e = [];
            i.ready = function (f: any) {
              i._e.push(f);
            };
    
            return i;
          }
        }(document, "script", "instagram-wjs");
    
        if ((<any>window).instagram.ready())
        (<any>window).instgrm.Embeds.process();
      }
    
    ionViewDidEnter() {
    instagramRender();
    twitterRender();
    }
    
    

    But when fetching data from an API and injecting HTML code dynamically like this:

    this.htmlContent = domSanitizer.bypassSecurityTrustHtml(this.postContent);
    instagramRender();
    twitterRender();
    

    For me, the Twitter and Instagram embeds have not been rendered even when calling the functions after the HTML assignment!

    It is a synchronization problem, since it seems that the functions are firing just before the dynamic HTML content are loaded!

    I had tried calling the functions after the div that I am injecting to it the HTML content is loaded. <div (load)="render()" [innerHTML]="htmlContent"></div> but it seems that the div has no "load" event in ionic!

    So, I had tried waiting for 200ms after filling the HTML content, and then calling the functions,and it worked like charm.

    setTimeout(() => {
          this.twitterRender();
          this.instagramRender();
       }, 200);
    

    SUCCESS!