In januari van dit jaar kondigde jQuery een nieuwe aan plug-ins register , dus nu leek het een goed moment om een ​​tutorial te schrijven waarin ik een jQuery-plug-in combineerde met mijn passie - realtime webtechnologieën.

Realtime webtechnologieën maken het heel eenvoudig om live content toe te voegen aan eerder statische webpagina's. Live-inhoud kan een pagina levend maken, gebruikers behouden en ervoor zorgen dat ze de pagina niet periodiek verversen. Realtime-updates worden meestal bereikt door verbinding te maken met een gegevensbron, zich te abonneren op de gegevens die u aan de pagina wilt toevoegen en vervolgens de pagina bij te werken zodra de gegevens binnenkomen. Maar waarom kan dit niet worden bereikt door simpelweg een pagina te markeren om te bepalen welke gegevens moeten worden getoond en waar? Nou ja, misschien kan het!

jQuery's slogan is minder schrijven, meer doen . De slogan voor de jQuery Realtime-plug-in die we in deze zelfstudie gaan bouwen, zal minder worden geschreven, realtime doen.

In deze zelfstudie maken we een jQuery-plug-in die het heel gemakkelijk maakt om realtime inhoud aan een pagina toe te voegen door simpelweg wat markeringen toe te voegen. Eerst bespreken we hoe een geroepen service te gebruiken Pusher om je te abonneren op realtime gegevens. Vervolgens definiëren we een manier om een ​​HTML5-document met 'data- *' kenmerken te markeren op een manier die vervolgens kan worden opgevraagd door onze realtime jQuery-plug-in en geconverteerd naar realtime gegevensabonnementen. Ten slotte maken we de jQuery-plug-in die de kenmerken gebruikt om zich te abonneren op gegevens en onmiddellijk updates op de pagina weer te geven.

Als je gewoon recht naar binnen wilt duiken, kan dat bekijk een demo in actie of je kunt download de code en begin met hacken.

Basis van de aandrukker

Pusher is een gehoste service waarmee u eenvoudig realtime inhoud en interactieve ervaringen kunt toevoegen aan web- en mobiele apps. Hier gaan we eenvoudigweg verbinden, abonneren op sommige gegevens en vervolgens een pagina bijwerken wanneer de gegevens binnenkomen.

Om dit aan te tonen, maakt u een bestand aan met de naam 'example.html' en neemt u de Pusher JavaScript-bibliotheek op vanaf het Push CDN. We weten dat we jQuery 2.0.0 gaan gebruiken, dus we moeten dit nu ook opnemen:

Creating a realtime jQuery plugin | Webdesigner Depot

Aansluiten

Zodra de Pusher JavaScript-bibliotheek is opgenomen, kunnen we verbinding maken met Pusher door een nieuwe 'Pusher' -instantie te maken en een toepassingstoets door te geven. Maak een extra '

Note: For the tutorial we’ll use an application key that I’ve provided but for your own applications you’ll need to sign up to Pusher to get your own.

You can check that you’re connected in three different ways. You can do it manually by checking the Pusher Debug Console, if you load the page with the Pusher Debug Console open you’ll see the connection logged. The Pusher JavaScript library provides a log property that you can assign a function to and then you can manually check to make sure a connection has been established by inspecting the browser’s JavaScript console. Or you can check the connection programmatically by monitoring the connection state of the Pusher instance.

pusher_001

The Pusher Debug console

Whatever you choose to do, you’ll now be connected.

Subscribe

Pusher uses the Publish & Subscribe pattern, so to receive data from Pusher you first need to subscribe to it. Pusher uses the term channels when it comes to subscriptions, so let’s subscribe to a channel called ‘test-channel’.

As with connection state, you can check the status of a subscription in a few ways; using the Pusher Debug Console, by checking the output from ‘Pusher.log’ or by binding to the ‘pusher:subscription_succeeded’ event.

pusher_002

Using Pusher.log to log pusher-js library information

Bind to events

Those of you who use jQuery will probably be familiar with the idea of binding to events. jQuery does provide shortcuts for some events (e.g. ‘.onclick( )’) but you can also bind to events using ‘.bind(, )’. Pusher follows this convention and you can bind to events to be informed when something updates; when the connection state changes, when a subscription succeeds or when new application data is received. For this example, and with the realtime plugin, we’re interested primarily in the latter.

Let’s bind to a ‘test-event’ on the channel:

When binding to an event you simply identify the event by name and pass in a reference to a function that will be called when that event occurs (is triggered) on the channel.

If you have a Pusher account you can test that the ‘handleEvent’ function is called by using the Pusher Event Creator; enter ‘test-channel’ as the channel name, ‘test-event’ as the event name and some data (‘{ “some” : “data” }’) into the event data text area and click the submit button. You’ll then see the debug information, along with the data you entered, logged to the JavaScript console.

pusher_003 

Triggering an event from the Pusher Event Creator and logging it in the JavaScript console

Since the realtime jQuery plugin that we’re building doesn’t publish (trigger) data (it just consumes it) we won’t cover that here. But if you’re interested in finding out more checkout the Pusher server docs.

Displaying realtime updates

The next thing to consider is displaying the realtime data updates to the user.

For this we’ll need an idea for a simple application; having worked in finance for a few years I’m generally keen to avoid any type of financial example, but Bitcoin has made it interesting and relevant. So, let’s create a very simple display for showing Bitcoin prices.

Note: We’re going to use some fake data. Let’s make sure this doesn’t result in more Bitcoin panic selling!

First, let’s create some HTML where we’ll display the realtime prices. We can pre-populate the display with prices known at the time the page was loaded:

Bitcoin Fake Prices

LastLowHighVolume
BTC/USD61.157 USD51 USD95.713 USD66271 BTC / 4734629 USD

Let’s update the JavaScript to subscribe to a more appropriately named channel called ‘btc-usd’ and bind to a ‘new-price’ event:

The ‘data’ sent to the ‘handleEvent’ function should also be in a more appropriate format – here’s the JSON:

{"last": "last value","low": "low value","high": "high value","volume": "volume value"}

Now that we know this we can change the ‘handleEvent’ function to update the appropriate cell in the table:

function handleEvent( data ) {var cells = $( '#bitcoin_prices tbody tr td' );cells.eq( 1 ).text( data.last );cells.eq( 2 ).text( data.low );cells.eq( 3 ).text( data.high );cells.eq( 4 ).text( data.volume );}

If you now trigger a ‘new-price’ event on the ‘btc-usd’ channel, using the JSON we defined, the page will update to show the new values.

There are ways of both making this code nicer and, as the page grows to show more data, optimise things. But, we’re going to make it so that realtime data will be added to the page simply by applying markup.

Before we progress, let’s first add a bit of styling to the example. In the ‘’ add the following CSS:

As you can undoubtedly tell, I’m no designer. So please feel free to improve on this.

pusher_004

The “styled” Bitcoin Fake Prices application

Finally, restructure things so we’re set up for building the plugin.

  1. Create an ‘examples’ directory and within it a ‘bitcoin’ directory.
  2. Move the ‘example.html’ file to ‘examples/bitcoin’, rename it ‘index.html’.
  3. Create a ‘src’ directory at the top-level of the project.

The directory structure should now look as follows:

/
examples/
bitcoin/
index.html
src/

We’re now ready to define our realtime markup and build the realtime jQuery plugin.

Realtime markup

The first thing to highlight is that this isn’t a new idea — I worked for a company called Caplin Systems and in 2001 they had a technology known as RTML that let you markup a page so that realtime updates could be applied. The purpose here is to use jQuery to parse the page and then interpret the markup, resulting in subscriptions, event binding and ultimately live content being added to the page.

For our plugin we’ll use HTML5’s data-* attributes. These attributes don’t directly affect the layout or presentation of the page so they’re a great choice for our realtime markup.

The questions we now need to answer about the markup are:

  • Where do we put the Pusher application key?
  • How do we identify what channels should be subscribed to?
  • How do we identify the events that should be bound to on a channel?
  • How do we know what data to display in the page, and where?

The first one is relatively easy. Since we need to include our plugin JavaScript file we can add a ‘data-rt-key’ attribute to the ‘

So, from the script tag you can see we’re going to connect to Pusher using the key identified by ‘data-rt-key’. We’re going to subscribe to the ‘btc-usd’ channel and bind to the ‘new-price’ event. When an event is received we’re going to update the appropriate table cell based on the value indicated by ‘data-rt-value’; if the value of the attribute is ‘last’ then the value of the ‘last’ property is taken from the received ‘data’ object and displayed in the cell.

Hopefully what we are trying to achieve is now pretty clear. Let’s start looking at how to create a jQuery plugin.

jQuery plugin basics

The jQuery plugin creation docs are pretty good so I won’t go into the details here. We’ll simply concentrate on building the functionality that we need in our plugin.

Before we write any code we should consider how we want to use the plugin. The normal way a plugin functions is that you use jQuery to query the page, and then you execute the plugin functionality against the matched elements.

$( 'a' ).toggle();

The above code would find all ‘’ elements and then execute the ‘toggle()’ functionality on them — probably hiding all anchors, so not the most useful example you’ll ever see.

So, let’s say we would want to use the plugin as follows:

Laten we kijken naar het creëren van de verwachte functionaliteit.

Een realtime plug-in

Maak eerst een 'realtime.jquery.js' bestand in de 'src' directory. Dit bestand bevat de plug-in-functionaliteit. Voeg vervolgens het volgende toe aan het bestand als startpunt van onze plug-in:

( function( $) {$.fn.realtime = function() {console.log( 'realtime!' );console.log( $( this ).html() );}  ;} (jQuery)); 

We kunnen dit zelfs nu testen. Verwijder in 'voorbeelden / bitcoin / index.html' de voorbeeldplugin '

Als u de pagina nu vernieuwt, ziet u 'realtime!' ingelogd op de JavaScript-console samen met de HTML van de '

'element. Dit is geweldig want het betekent dat de plug-in werkt; we voeren onze plugin-functionaliteit met succes uit in de tabel die wordt geïdentificeerd door de selector die we hebben doorgegeven aan jQuery.

pusher_005

jQuery-invoegtoepassingen en bibliotheken van derden

Onze realtime plug-in is afhankelijk van een externe bibliotheek - de Pusher JavaScript-bibliotheek. Voorlopig hebben we het statisch opgenomen in onze HTML, maar we willen niet dat dit een vereiste is om de plug-in te gebruiken. Laten we het dus dynamisch laden. jQuery biedt een manier om dit eenvoudig te doen in de vorm van de '.getScript ()' functie.

Laten we dus versie 2.0 van de Pusher JavaScript-bibliotheek laden. We laden de door HTTPS gehoste versie in, zodat browsers tevreden zijn als onze plug-in wordt gebruikt op een pagina die via HTTPS wordt weergegeven (Chrome blokkeert al pogingen om door HTTP gehoste scripts op HTTPS-pagina's te laden en Firefox doet dit in Firefox 23 ). Ik ga het laden van de bibliotheek in een functie als volgt inpakken:

var libraryLoaded = false;function loadPusher() {$.getScript( "https://d3dy5gmtp8yhk7.cloudfront.net/2.0/pusher.min.js" ).done( pusherLoaded ).fail( function( jqxhr, settings, exception ) {console.log( 'oh oh! ' + exception );}  );} function pusherLoaded (script, textStatus) {libraryLoaded = true; console.log ('pusher.min.js loaded:' + textStatus);} loadPusher (); 

Als u de pagina opnieuw laadt, wordt het bericht 'pusher.min.js loaded: success' in de console vastgelegd.

Tijdens de ontwikkeling is het altijd goed om een ​​manier te hebben om informatie te registreren, dus laten we nu een eenvoudige 'log' -functie maken die we kunnen gebruiken en die zich gewoon bij de console aanmeldt. We zullen dit nu gebruiken en het ook gebruiken voor het loggen van Pusher-evenementen. De volledige bron van de plug-in is nu:

( function( $ ) {function log( msg ) {console.log( msg );}var libraryLoaded = false;function loadPusher() {$.getScript( "https://d3dy5gmtp8yhk7.cloudfront.net/2.0/pusher.min.js" ).done( pusherLoaded ).fail( function( jqxhr, settings, exception ) {log( 'oh oh! ' + exception );}  );} function pusherLoaded (script, textStatus) {libraryLoaded = true; Pusher.log = log; log ('pusher.min.js loaded:' + textStatus);} $. fn.realtime = function () {log (' realtime! '); log ($ (this) .html ());}; loadPusher ();} (jQuery)); 

U ziet ook dat we de functie 'log' hebben toegewezen aan de eigenschap 'Pusher.log'. Dit betekent dat we zowel de interne logboeken van de Pusher-bibliotheek als die van ons kunnen zien.

Wanneer moeten we verbinding maken?

Vanwege het asynchrone karakter van het laden van de bibliotheek kunnen we niet garanderen dat deze is geladen wanneer onze plug-in wordt geactiveerd. Helaas maakt dit de zaken een beetje ingewikkelder dan ideaal, maar we zullen proberen het zo eenvoudig mogelijk op te lossen.

We moeten controleren om te zien of de bibliotheek is geladen - vandaar de 'libraryLoaded'-vlag - en dienovereenkomstig handelen; als de bibliotheek is geladen, kunnen we verbinding maken, als dit niet het geval is, moeten we de uitvoering in de wachtrij plaatsen totdat dit het geval is. Daarom is het logischer om alleen de Pusher-instantie te maken wanneer we deze echt nodig hebben, en dat is wanneer we ons daadwerkelijk willen abonneren op gegevens.

Laten we kijken hoe we dat kunnen doen:

var pending = [];function pusherLoaded( script, textStatus ) {libraryLoaded = true;while( pending.length !== 0 ) {var els = pending.shift();subscribe( els );}}function subscribe( els ) {}$.fn.realtime = function() {var els = this;if( libraryLoaded ) {subscribe( els );}else {pending.push( els );}};

Wanneer de plug-in wordt genoemd, controleren we de 'libraryLoaded'-vlag om te zien of de Pusher JavaScript-bibliotheek is geladen. Als dat zo is, zijn we goed om te gaan en kunnen we ons abonneren. Als het nog steeds in behandeling is, moeten we de abonnementen in de wachtrij plaatsen. We doen dit door de jQuery-verzameling ('els') op een 'in behandeling zijnde' array te plaatsen.

Nu, maak verbinding

Nu we weten dat de Pusher JavaScript-bibliotheek is geladen en dat de pagina zich wil abonneren op gegevens, kunnen we onze instantie 'Pusher' maken. Omdat we slechts één 'Pusher' instantie per pagina willen, volgen we de Singleton patroon en heb een 'getPusher ()':

var pusher;function getPusher() {if( pusher === undefined ) {var pluginScriptTag = $("script[src$='jquery.realtime.js']");var appKey = pluginScriptTag.attr("data-rt-key");pusher = new Pusher( appKey );}return pusher;}

Deze functie grijpt de plug-inscripttag door te zoeken naar een tag met een 'src' -kenmerk dat eindigt op 'jquery.realtime.js' en krijgt vervolgens de waarde van het kenmerk 'data-rt-key'. Vervolgens wordt er een nieuwe instantie 'Pusher' gemaakt die de sleutel doorgeeft. Zoals eerder besproken, resulteert het maken van een nieuwe instantie 'Pusher' in een verbinding met de bron van onze gegevens.

abonneren

We kunnen nu de functie 'getPusher ()' gebruiken wanneer we toegang willen krijgen tot de instantie 'Pusher'. In ons geval willen we het gebruiken wanneer we de elementen analyseren om abonnementen te bepalen.

Werk de functie 'Abonneren' van de tijdelijke aanduiding bij en voeg de aanvullende functies hieronder toe:

function subscribe( els ) {var channelEls = els.find( "*[data-rt-channel]" );log( 'found ' + channelEls.size() + ' channels' );channelEls.each( subscribeChannel );}function subscribeChannel( index, el ) {el = $( el );var pusher = getPusher();var channelName = el.attr( 'data-rt-channel' );var channel = pusher.subscribe( channelName );}function find( els, selector ) {var topLevelEls = els.filter( selector );var childEls = els.find( selector );return topLevelEls.add( childEls );}

De 'vind'-functie is een utiliteitsfunctie om elementen uit een bestaande verzameling te gebruiken die overeenkomen met een bepaalde selector '.filter()', samen met eventuele nazaten van de elementen die gebruiken '.vind()'. We gebruiken deze functie om elementen te vinden die zijn gemarkeerd om kanaalabonnementen weer te geven ('data-rt-channel'-attribuut) en voor elke die we vervolgens' subscribeChannel 'noemen. Deze functie extraheert de naam van het kanaal waarop moet worden geabonneerd en gebruikt de waarde bij het aanroepen van 'pusher.subscribe (channelName)' om zich daadwerkelijk op het kanaal te abonneren.

Binden

Vervolgens moeten we elementen vinden die zijn gemarkeerd om gebeurtenissen weer te geven (kenmerk 'data-rt-event') waaraan moet worden gebonden:

function subscribeChannel( index, el ) {el = $( el );var pusher = getPusher();var channelName = el.attr( 'data-rt-channel' );var channel = pusher.subscribe( channelName );var eventEls = find( el, '*[data-rt-event]' );log( 'found ' + eventEls.size() + ' events' );eventEls.each( function( i, el) {bind( el, channel );} );}function bind( el, channel ) {el = $( el );var eventName = el.attr( 'data-rt-event' );channel.bind( eventName, function( data ) {displayUpdate( el, data );} );}function displayUpdate( el, data ) {}

Voor elk element van de gebeurtenis vinden we oproepen onze eigen 'bind' functie die zich bindt aan de gebeurtenis op het kanaal met behulp van 'channel.bind (eventName, eventHandler)'. De gebeurtenishandlerfunctie is een kleine afsluiting waarmee we de gegevensupdate, indien ontvangen, en het gebeurteniselement kunnen doorgeven aan een 'displayUpdate'-functie.

Als we dit nu uitvoeren, kunnen we aan het loggen zien dat er een verbinding tot stand is gebracht, we vinden één kanaal en abonneren het en vinden één gebeurtenis om aan te binden.

pusher_006

jQuery realtime markup kanaal zoeken abonnement en event binding

Toon de update

Wanneer de gebeurtenishandler wordt aangeroepen, moeten we de naam van elke eigenschap op het object 'data' (bijv. Last, low, high en volume) vinden die met de update is verzonden en elementen vinden die met die naam zijn gemarkeerd.

function bind( el, channel ) {el = $( el );var eventName = el.attr( 'data-rt-event' );channel.bind( eventName, function( data ) {displayUpdate( el, data );} );}function displayUpdate( el, data ) {for( var propName in data ) {var value = data[ propName ];var updateEls = find( el, '*[data-rt-value="' + propName + '"]' );log( 'found ' + updateEls.size() + ' "' + propName + '" elements to update' );updateEls.text( value );}}

We lus over het object 'data' en krijgen de naam van elke eigenschap. Zodra we de eigenschapnaam ('propName') kennen, kunnen we de bijbehorende elementen vinden en hun tekstwaarde bijwerken met de nieuwe gegevenswaarde. Voor nu ondersteunen we geen objecten met enige vorm van hiërarchie - we willen slechts één niveau van sleutel- en waardeparen.

Als u nu de pagina vernieuwt en een gebeurtenis van de Pusher Event Creator activeert, worden de nieuwe gegevens onmiddellijk op de pagina weergegeven.

Heb je gewerkt met een live dataservice? Welke lessen heb je geleerd? Laat het ons weten in de comments.

Uitgelichte afbeelding / thumbnail, live data-afbeelding via Shutterstock.