createTweetEmbed() throws TypeError when node removed


#1

I’m showing users tweets given some server-cached information. The template looks like this (underscore.js syntax):

<%- document.text %>

—<%- url.username %> ...

And as soon as the page is loaded, I call this (CoffeeScript syntax, assuming twttr.js is loaded):

          blockquote = @$('blockquote')[0]
          id = blockquote.getAttribute('data-tweet-id')

          twttr.widgets.createTweetEmbed id, blockquote.parentNode, ->
            $(blockquote).remove()

This correctly replaces the blockquote with the tweet.

However, if I remove the DOM element (the whole thing, plus its parent) from the page before Twitter’s server responds with the tweet JSON, I get an icky error with this stack trace:

Uncaught TypeError: Cannot read property 'display' of undefined widgets.js:35
(anonymous function) widgets.js:35
k.aug.callIfSandboxReady widgets.js:33
k.aug.callsWhenSandboxReady widgets.js:33
t.fetchAndRender.l.tweets.complete widgets.js:35
b widgets.js:29
(anonymous function) tweets.json:1

I can’t see any way of catching the error, as my code isn’t throwing it. My app seems stable enough, but it’s frustrating to debug.

Can I (or Twitter) solve this problem? I’m hoping it’s an easy fix somewhere…


#2

Hi Adam,

Interesting race condition, I’ll definitely look to add some catches against that; thanks for the information.

One thing with your example: You seem to be outputting a full

embed code in your page itself. As such, rather than using createTweet, you could instead just use twttr.widgets.load with an optional root to initialize all the blockquotes at once.

As well as saving you the need to manually invoke them, it will also fetch all of the Tweets with a single HTTP request. Currently, createTweet makes one request per call. (Although, on that, I have a post-it note on my monitor to implement a batch version of the function when I next get a chance.)

Regards,

Ben


#3

Hi Ben,

Thank you for your suggestions. In our case, there can only be one tweet (this is an iframe whose sole purpose is to show a tweet). We render the whole blockquote as a fallback: if people upload a private tweet to us, for instance, Twitter won’t render the tweet. For your own curiosity, our logic is here: https://github.com/overview/overview-server/blob/master/app/assets/javascripts/apps/DocumentDisplay/views/Page.coffee#L113-L154

That brings up a second question, while I have your ear: is there a way to get twttr to call a callback I specify if tweet-loading fails?


#4

Hi Adam,

So, at present, the callback is only triggered on successful loads. However, with embedded Timelines we pass either the successfully created element, or an HTTP error code. I’ll check into why that isn’t happened with the individual Tweets.

That bug notwithstanding, it’s worth noting there are still cases where you’d simply hit a timeout (e.g. if our server was temporarily down and no response, 404 or otherwise, comes back.) For now, you should implement your own timeout-based handler, and disable it using the success callback when it fires. I’ll look into filling out the known-errors support when I get a chance.


#5