Bootstrap Modal Dynamic Youtube Embed, JavaScript

Using Twitter Bootstrap 3.0, I wanted to use its modal window to open YouTube videos.

Rather than manually placing  the HTML for each video’s modal, or creating a line of JavaScript for each separate video, I wanted any YouTube link to pop up embedded in a modal window, without extra code. The modal is a progressive enhancement. The link should work normally without any JavaScript. You could also disable the modal functionality for small devices on a responsive design.

Let’s say I have a link on the page in one of the following formats:

In order to generate an iframe embed code, we’ll first need to get the video ID from the URL. Then, put this video ID into the iframe embed format that YouTube gives you under “Share”, and open that in a modal.  I’ve added the data-width and data-height attributes, which will be used to determine the size of the modal window and embed. If these are not set, a default size will be used.

Modal HTML

I’m going to use empty modal HTML that’s placed right before the closing body tag, rather than using an external page. Note the ID, “mediaModal”, which will be used in the JavaScript. This is the basic modal template provided on the official Bootstrap 3.0 docs.

This only needs to be included on the page once, as multiple videos will open in this same modal container:

jQuery – Open all YouTube video links in a modal window

Explanation

First we find all links that begin with http://www.youtube.com, using the attribute-starts-with selector. Then we need to get the video ID from the video URL. I decided to use the plugin on GitHub “jQuery Query Parser” (open source MIT license), to parse out the query string variables and their values. This makes it a little more future-proof, as it will better handle URLs that contain more parameters (HD, rel=0, etc) and malformed links. The minified version of this plugin is pretty small.

The script then goes and inserts the YouTube iframe HTML into the contents of .modal-body inside of #mediaModal. If you use the data-height and data-width, they’re used in the embed, else it defaults to 560×315.

Twitter bootstrap’s modal window is a little limited, compared to some lightboxes. It will not dynamically size itself to fit the content, though you can have it be a percentage width via CSS for responsive sites. In this case, I’d like the window to be just big enough for the video, so that requires calculating a few widths.

The .modal-body and .modal-dialog elements both default to having padding, that could be modified in your CSS. So the script adds the left and right padding of both, to the width of the video, in order to get the final width that the .modal-dialog container should be. This is hooked into the show.bs.modal event.

Then finally, the modal window is opened with modal().

Note: Bad NPObject? Blocked a frame with origin?

If the iframe code that isn’t being inserted into the DOM does not include &wmode=transparent on the src link (it does in the above example), you may start getting these errors:

  • Chrome: Blocked a frame with origin “http://www.youtube.com” from accessing a frame with origin
  • Firefox:  Error bad NPObject

This caused a lot of frustrations, because everything online was saying that this was a cross-domain issue or a browser bug, etc. The video would work in Chrome, but would be black and not work in Firefox. Hopefully that helps if you’re struggling with the same issue! Note that Chrome will still give an origin error from within the frame which will not stop JS processing on your page, and appears to be a bug in Chrome that isn’t fixed yet (per some StackOverflow posts). The video still plays and operates fine.

 

 

Comments on this Article

  1. Justin says:

    This is pretty great.. thank you for sharing.

    I have a question though. *I’m a novice with JQuery and JavaScript*

    I have around 20 unique modals (bootstrap 3) on my site. Each modal has a unique youtube video embedded in it. To do this for my site, do you recommend I script this JQuery 20 different times, each with the appropriate corresponding Modal ID?

    Thanks so much..

    Justin

    • Josh says:

      I wrote this script to avoid and replace the type of situation you are describing, where there are 20+ unique modal IDs. I try to stick to the DRY principle (Don’t Repeat Yourself). It only requires the single “Video / Generic Modal” HTML, and then the embed code is dynamically inserted into that. If the modals are only for video (no other content), then this script could be used to replace all of those.

  2. Brian says:

    Do you have a link showing this in action? I think its what I want, but would like to eyeball it. Thanks.

    • Josh says:

      Not at the moment, sorry. I can’t link to the particular project I created it for. I’ll have to set up a demo in a new bootstrap site.

  3. crazy4groovy says:

    “&wmode=transparent” is PURE GOLD! Thanks man!!

  4. Derrick says:

    For a responsive modal that automatically sizes the modal to fit the current display, change these three lines:

    // Variables for iFrame code. Width and height from data attributes, else use default.
    var vidWidth = 560; // default
    var vidHeight = 315; // default

    …to this:

    // Calculate default iFrame embed size based on current window size
    // (these will only be used if data attributes are not specified)
    if ($(window).height() < $(window).width()) {
        var vidHeight = $(window).height() * 0.7;
        var vidWidth = vidHeight * 1.77777;
    } else {
        var vidWidth = $(window).width() * 0.9;
        var vidHeight = vidWidth / 1.77777;
    }
    

    I wanted to submit this to the gist repo, but couldn't find a way to do so.

    • Josh says:

      Great. Thanks for sharing.
      I think it’d be a good idea to add a max width too, so the video does not get too huge/stretched for giant monitors (or else a max-width may be on the modal itself).

  5. Faiz says:

    Thanks a lot. Useful Code :)

  6. Gregor Volkmann says:

    Thanks, helped me with my Bandspage! But I don’t like your approach on using the jQuery Parser, I just did:

    var queryStringArray = queryString.split("&");
    var queryVars = new Array();

    for(i = 0; i < queryStringArray.length; i++) {
    queryVars[queryStringArray[i].split("=")[0]] = queryStringArray[i].split("=")[1];
    }

    Results in one less dependency.

    Cheers, Gregor from My Friend The Immigrant

  7. matt says:

    Weird, embedded Gist’s don’t show up in Chrome on Mac…

    Refused to execute script from 'https://gist.github.com/cf4add71f2d3e138cdd3.js?file=' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled. www.joshuawinn.com/:1
    Refused to execute script from 'https://gist.github.com/0e936461be263d7e7474.js?file=' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled. www.joshuawinn.com/:1
    Refused to execute script from 'https://gist.github.com/6655039.js?file=' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled. www.joshuawinn.com/:1

    • Josh says:

      Odd..are you still receiving this error? I saw a few issues about this online related to the nosniff header and RAW.github.com, but this really shouldn’t be happening with GIST.github.com’s embed, unless its a problem with the plugin that displays it. I hope it was a temporary issue.

Leave a Reply

You can use the <pre> tag to post a block of code, or <code> to highlight code within text.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>