Recently I’ve answered a couple of questions from people that had a section of their site loaded dynamically with Javascript, and wanted to put a +1/Sign-In/Follow/etc button there. Google+ Sign-In along with all the Google widgets, can be marked up in HTML and rendered automatically when the plusone.js loader is included in the page. However, there are ways of controlling when that happens with explicit parsing, or triggering it directly with the render functions.
Lets say we have a page that contains a +1 button, a follow button and a post embed, though the same thing works with sign in, badges, and anything else. The most straightforward way to write that page is by using the markup based widgets, which all follow a similar form and look something like this.
Pretty much all the other widgets work the same way: a known class name which is scanned for when the async tag loads, and a series of parameters on the element specified as data- attributes to configure the behaviour of the widget. If we put this into a page, it loads and looks like this.
When plusone.js has loaded it automatically replaced the contents of the elements with the relevant widget. In some cases, such as interactive posts and sign-in, if there is already content in the tag it will be retained and a click handler added to trigger the appropriate behaviour instead. Of course, we might not want to do this right away, or we might want to bring in some element of a page dynamically. We can suppress the automatic parsing by using the parsetags config setting in the standard Google Javascript API config dictionary. This is generally best done at the top of the page, or in any case before plusone.js is loaded.
Now we can choose when to render the buttons by calling gapi.*.go(), where * is replaced with the type of widget we’d like to render. We can either call go() directly for each widget type, which will render all elements of that the of the page, or we can specify a container as the first argument to the go call. This is not the id of the element itself, but of a parent of that element. All widgets within the container will be rendered, but ones outside wont. In the example below, we’ll attach the go calls to a button click:
In this snippet we have a function which is going to enable a button, and attach the click handler to it. When the button is clicked it will call go() for the plusone and follow widgets wherever they are, but only for the post widget within the element with ID postcontainer. Then, if our HTML looks like this:
The first post embed is within the postcontainer element, the second is not. When we hit the go button, only the first is rendered.
You might also have noticed that we only added the go button in a function. This is taking advantage of an extremely handy feature of the plusone.js loader. If you specify an ?onload=… parameter on the URL, it will call that function once the Google API client has loaded. You may also note I have client: prefixed to the filename. This means the loader comes with the client for API calls as well - we’re not using that here, but I tend to, so this is the form of the async snippet I most commonly use.
We have a third option with rendering as well, and this is my preferred one. We can trigger the rendering directly with gapi.*.render, where again * is any of the widget types. The nice thing about this is that we can set all the properties in an options dictionary, so we can pass in closures and not be required to have global functions for things like callbacks. This also means that you can centralise your various bits of widget configuration more easily!
The first parameter to the render methods is either the ID of an element, or the element itself - not the container this time. The second argument is the options bundle, where we specify the information that was previously in data- attributes. This also means that instead of specifying data-callback=”function_name” on the sign-in button, for example, we could actually inline the function, or refer to a function in another object. Notice that for the plusone and the follow buttons we’re passing the element ID, but for the post we’re passing the element itself. Either is valid!
In our example, we’ll trigger the gapi.*.render calls in the startRender callback from the plusone.js loading, so we’ll get the same effect as in the first post:
This time though, the actually HTML behind it is much simpler, as all of the attribute information is contained in the Javascript.
So, for any kind of content we can trigger rendering whenever we need, and by using the callback on the plusone.js loader we can be sure that all of the requisite Google Javascript code will be available.