November 2008 - Posts

Jag sitter för tillfället på ett flyg som är hyfsat försenat på grund av det härliga ovädret, så jag passade på att skriva en liten post om hur man använder jQuery för att hämta data asynkront med ett visst tidsintervall. Jag åkte 16:15 från Umeå, sen var vi över Stockholm i en halvtimme och är sedan runt 18 i Nyköping på grund av att det snöade för mycket på Arlanda (klockan är för tillfället 20:00)... Härligt, härligt! :-)

För att hämta data asynkront med jQuery så finns det en inställning som sätter cachen i webbläsaren. Den skall vi använda för att förhindra att datan cachas av webbläsaren, vilket skulle ge felaktiga resultat. Sedan använder vi en standardmetod i javascript för att anropa vår metod var 1000:e millisekund (dvs varje sekund).

Det som skall hämtas är aktuell tid från servern, och det presenteras via en web handler.

Först och främst så behöver vi en enkel HTML-sida:

 

   1:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   2:  <html xmlns="http://www.w3.org/1999/xhtml">
   3:  <head runat="server">
   4:      <title>Ajax</title>
   5:      <script src="scripts/jquery-1.2.6.js" type="text/javascript"></script>
   6:      <script src="scripts/ajax.js" type="text/javascript"></script>
   7:  </head>
   8:  <body>
   9:      <div id="currentTime"></div>
  10:  </body>
  11:  </html>

Tiden skall visas i klartext i div-elementet med ID satt till "currentTime". För att förhindra att HTML skickas in (vilket skulle kunna bero på någon sårbarhet i metoden som returnerar tiden) så använder vi text-metoden i jQuery.

   1:  $().ready(function() {
   2:      ShowCurrentTime();
   3:      window.setInterval('ShowCurrentTime()', 1000);
   4:  });
   5:   
   6:  function ShowCurrentTime() {
   7:      $.ajax({
   8:          url: "currenttime.ashx",
   9:          cache: false,
  10:          success: function(result) {
  11:              $("#currentTime").text(result);
  12:          } 
  13:      });
  14:  }

Det som sker här är att vi först anropar metoden "ShowCurrentTime()" vid sidans laddning och då visar aktuell tid, sedan anropar vi den igen var 1000:e millisekund. Metoden window.setInterval() är en standardmetod i javascript som stöds av alla moderna webbläsare.

För att hämta datan så använder vi ajax-metoden i jQuery som låter oss skicka med en mängd inställningar, vilka som finns kan ni hitta i dokumentationen. Vi anropar currenttime.ashx med cachning inaktiverad och visar sedan (vid lyckad hämtning) resultatet i klartext i div-elementet.

Web handlern som används är en väldigt enkel och som enbart returnerar tiden i klartext.

 

   1:  <%@ WebHandler Language="C#" Class="currenttime" %>
   2:  using System;
   3:  using System.Web;
   4:   
   5:  public class currenttime : IHttpHandler {
   6:      public void ProcessRequest (HttpContext context) {
   7:          context.Response.ContentType = "text/plain";
   8:          context.Response.Write(DateTime.Now.ToLongTimeString());
   9:      }
  10:   
  11:      public bool IsReusable {
  12:          get {
  13:              return false;
  14:          }
  15:      }
  16:  }

Nu fick jag just höra att planet är tankat och redo att cirkulera runt Arlanda i ett par timmar, så förhoppninsvis så kommer jag hem ikväll. När det här postas så vet ni iaf att jag överlevde resan! ;-)

Jag kan meddela att vi landade på Arlanda strax efter 22.. Jippi!

Först måste jag bara säga att jQuery har vuxit explosionsartat på Aspsidan, kul! Personer som tidigare har varit livrädda för att ta tag i det läskiga script-språket “javascript” har helt plötsligt insett hur kul det kan vara. Javascript är något som alla webbutvecklare älskar att hata.

Genom nästan alla år som jag har utvecklat för webben så har javascript funnits runt hörnet, och det är trots att det har funnits så länge ändå varit något föraktat. Många ser det som något som är omöjligt att utveckla i och vill inte ta i det med tång. Tack vare jQuery verkar nu detta vara på väg att förändras. Äntligen!

Det för dock inte bara med sig guld och gröna skogar. Något man aldrig ska glömma är att det faktiskt är javascript man fortfarande jobbar med, men med ett bibliotek som underlättar vid arbetet. Det underlättar oerhört mycket vid många tillfällen där man tidigare har behövt anpassa koden för olika webbläsares olika tolkningar av ECMAScript, vi har JavaScript från gamla trotjänaren Netscape, men som nu finns i olika varianter i Firefox, Opera, Safari med mera, och så har vi har JScript för Internet Explorer. Det alla dessa har gemensamt är att de bygger på ECMAScript, men ofta har sina egna funktioner anpassade för just den webbläsaren. Samma funktion kan även ha olika sätt att lösas på i olika tolkningar, som till exempel attributes[“namn på attribut”] och getAttribute()/setAttribute(). Sådana saker har vi tidigare behövt kolla upp och sedan sätta/hämta på olika sätt, beroende på hur den aktuella webbläsaren har implementerat funktionen. Med jQuery kan vi istället använda antingen selectors ($(‘a[href=”http://www.example.org”’)) eller med attr-metoden i jQuery ($(‘a’).attr(‘href’).

När vi sedan använder standard-funktioner i javascript så får vi fortfarande se upp för de missöden olika webbläsares tolkningar kan leda till. Glöm aldrig det!

Det var dock ej det som den här bloggposten skulle handla om, utan nu handlar det om hur man bygger ut jQuery. Det jag ska visa är hur man kan skapa funktioner som anropas genom jQuery.

När man vill bygga ut jQuery med egna funktioner så finns det något som heter “fn” i det. För tillfället så finns det olika metoder för slide, som slideUp och slideDown. Det vi vill ha är en metod som heter slideUpAndDown() och som skall köra först slideUp och sedan slideDown. Denna metod skall kunna anropas genom att vi kör $(‘div’).slideUpAndDown(). Den kommer alltså att finnas med i kedjan av funktioner som jQuery erbjuder.

Det första vi behöver är HTML-koden som skall användas:

   1:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   2:  <html xmlns="http://www.w3.org/1999/xhtml" >
   3:  <head runat="server">
   4:      <title>jQuery - SlideUpAndDown()</title>
   5:      <script type="text/javascript" src="jquery-1.2.6-vsdoc.js"></script>
   6:      <script type="text/javascript" src="jquery.slideupanddown.js"></script>
   7:  </head>
   8:  <body>
   9:      <div id="slider">
  10:          Test
  11:      </div>
  12:      <button id="btnSlideUpAndDown">Slide up and down!</button>
  13:  </body>
  14:  </html>

Ingenting konstigt här. Vi har en div med id “slider” som skall åka upp och ned, samt en knapp som ska trigga funktionen. Jag har även inkluderat två js-filer, dels jQuery-filen med intellisense-stöd, men så även jquery.slideupanddown.js som är vår funktion. När man skriver plugins till jQuery så bör filen alltid ha namnet jquery.funktionensNamn.js. Det är för att man dels ska veta att det är en funktion till detta, samt även för att man enkelt skall se namnet på funktionen. Det underlättar mycket när man har flera olika plugins.

Nu när vi har en färdig HTML-kod att testa funktionen mot så skall vi även skriva funktionen. När man skriver funktioner för jQuery så använder man som jag nämnde tidigare en metod som heter “fn”.

En enkel utbyggnadsfunktion som heter slideUpAndDown och som helt enkelt skall anropa slideUp() och slideDown() på det eller de element som har skickats in via vanliga jQuery-selectors kan sedan se ut så här:

   1:  (function($) {
   2:      $.fn.slideUpAndDown = function() {
   3:          return $(this).slideUp().slideDown();
   4:      }
   5:  })(jQuery);

 

Vi kan alltså med fem rader skriva en enkel funktion som gör detta. Denna kan nu användas mot vilka element som helst på sidan, genom att vi använder selectors. När vi nu ska testa denna så kan vi använda den här koden:

   1:  $().ready(function() {
   2:      $('#btnSlideUpAndDown').click(function() { $('#slider').slideUpAndDown() })
   3:  });

Vi anropar den alltså på exakt samma sätt som alla andra jQuery-metoder. Då det är en utbyggnad av jQuery så kan vi använda oss utav den funktionskedja som jQuery erbjuder, och kan till exempel skriva så här:

$('#btnSlideUpAndDown').click(function() { $('#slider').slideUpAndDown().slideUp().slideDown(); })

Det är inte ofta som man bara vill använda hårdkodade värden i metoden, utan vi vill kanske ha olika egenskaper. Dessa skulle kunna skickas med som vanliga parametrar, så att vi har till exempel:

   1:  (function($) {
   2:      $.fn.slideUpAndDown = function(a, b, c, d, e, f, g, h, i, j) {
   3:          return $(this).slideUp().slideDown();
   4:      }
   5:  })(jQuery);

 

Detta blir dock väldigt fult då vi kanske bara vill ange värden för a och j, vilket betyder att anropet skulle innehålla en massa null-värden (den som har programmerat mot API:erna i windows, Internet Explorer, Office eller liknande vet exakt vilket helvete det blir med alla anrop som till exempel internet explorers Navigate2(“url”, null, null, null, null, null, null, null, false)). Detta vill vi absolut inte tvinga våra användare av funktionen till då det blir alldeles för fult och svårtolkat. Istället skall vi använda oss utav extend-metoden i jQuery som låter oss skicka in en JSON-sträng med alla parametrar vi vill sätta.

Det vi ska göra är att använda oss utav en parameter som sedan kan innehålla ett flertal värden i sig. Vi kallar denna parameter för “slideSettings”. Sedan skall vi ha en variabel i funktionen som dels sätter default-värden som används ifall inga andra har satts, samt även listan med värden som har satts och som då skall användas. Sedan använder vi dessa värden i funktionen.

Ett exempel på hur funktionen kan se ut med extend:

   1:  (function($) {
   2:      $.fn.slideUpAndDown = function(slideSettings) {
   3:          var settings = $.extend({ speedUp: 'slow', speedDown: 'slow' }, slideSettings || {});
   4:          return $(this).slideUp(settings.speedUp).slideDown(settings.speedDown);
   5:      }
   6:  })(jQuery);

 

Här har vi två inställningar, speedUp och speedDown, samt default-värden för dessa. När vi sedan kör slideUp och slideDown så skickar vi med dessa värden för att välja hur snabbt vårt element ska “slide:a”. Om inga värden har satts så kör vi med ‘slow’ både upp och ned. Om vi byter ut den gamla koden mot denna och kör så kan vi se direkt att elementet åker sakta både upp och ned. För att ändra dessa värden vid anropet så får vi byta ut koden för click-eventet mot denna:

   1:  $().ready(function() {
   2:  $('#btnSlideUpAndDown').click(function() {
   3:          $('#slider').slideUpAndDown({
   4:              speedUp: 'fast',
   5:              speedDown: 'slow'
   6:          })
   7:      })
   8:  });

 

Det vi gör här är att vi helt enkelt sätter speedUp till ‘fast’ och speedDown till ‘slow’ i en JSON-sträng. Annars är det exakt samma kod som vi hade innan.

Det vi har nu är en funktion som kan anropas genom det vanliga jQuery-biblioteket som om det vore en inbyggd funktion. Denna funktion har även inställningar för hastigheten och kan sättas direkt vid anropet. Då den bygger på jQuery så kan vi enkelt använda selectors för att sätta den på vilket element vi vill, det behöver alltså inte vara just en div som vi har här i exemplet.

Om någon av er som läser det här har skrivit egna funktioner så lämna gärna kommentarer med URL:er, alternativt koden direkt så vi andra kan ta del av dem.

För de som förstår det hemska med anropen till till exempel Internet Explorer eller Office lär uppskatta C# 4.0 som kommer att ha stöd för namngivna parametrar i och med de dynamiska anrop som kommer, vilket gör att man på ett liknande sätt kommer att kunna anropa metoder utan att behöva ange en radda med null-värden. Yay! :-)

More Posts