The Cache: Technology Expert's Forum
 
*
Welcome, Guest. Please login or register. September 21, 2019, 06:50:02 AM

Login with username, password and session length


Pages: [1]
  Print  
Author Topic: Building contemporary sites with CSS3, Javascript & jQuery  (Read 8571 times)
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« on: September 11, 2011, 12:25:28 PM »

This set of posts was started for Phaeton, who asked for advice on how to build this website...



.. for a job he's applying for. I thought I'd take the time to tear it apart piece by piece so that others can challenge/expand my ideas and create a little mini-tutorial on this sort of thing.

IMO, today's websites should use *only* structural HTML that contains no behavior or "look" markup. This is an excellent methodology for both SEO and programming, because it keeps content separate from look separate from behavior, yet leaves hooks for each to do their thing. It's with that in mind that I'll take on this site.

Please don't hesitate to jump in and question either the mechanisms or my methods. I also look forward to any feedback from smarties about how to go further or tighter with this design.

PLEASE NOTE: I'm not actually doing this page, I'm just typing, so there may be bugs along the way.

FURTHER EDIT: If you could give a shit about CSS but want to see the jQuery and Javascript bits, scroll down several posts.
« Last Edit: September 11, 2011, 08:42:25 PM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #1 on: September 11, 2011, 01:00:11 PM »

The HTML should be ultimately simple, with as few structural elements as possible, but enough for both our look and behavior team to be able to animate the site. I propose:


<body>
<header><navigation>
<div class="menu">
   <div class="menuItem" ref="home">Home</div>
   <div class="menuItem" ref="providers">Providers</div>
   <div class="menuItem" ref="practitioners">Practitioners</div>
   <div class="menuItem" ref="children">Children</div>
   <div class="menuItem" ref="reports">Reports</div>
   <div class="menuItem" ref="options">List Options</div>
   <div class="menuItem" ref="users">Users</div>
</div>
</navigation></header>

<div id="contentArea">
   <div id="searchBlock">
      <div id="searchCaption">Provider VPK Monitor Reports</div>
      <div id="searchParams">
         <div class="paramRow">
            <div class="paramCaption">Start Date:</div>
            <div class="paramList"
               <input id="editStartDate" type="text">
               <span id="captionEndDate">End Date:</span>
               <input id="editEndDate" type="text">
            </div>
         </div>
         <div class="paramRow">
            <div class="paramCaption">Provider:</div>
            <div class="paramList">
               <select id="selectProvider"></select>
            </div>
         </div>
         <div class="paramRow">
            <div class="paramCaption">User:</div>
            <div class="paramList">
               <select id="selectUser"></select>
               <input type="button" id="execSearch" class="paramButtons" value="Search">
               <input type="button" id="clearSearch" class="paramButtons" value="Clear">
            </div>
         </div>
      </div>
   </div>
   
   <div id="dataBlock">
      <div id="dataNav">
         <div id="dataLocation">Page: 1 of 9</div>
         <div id="dataGoTo">
            <div id="dataNext">Next >></div>
         </div>
      </div>
      
      <div class="dataHeader">
         <div class="dhDate dhHeader">Report Date/Time</div>
         <div class="dhProvider dhHeader">Provider</div>
         <div class="dhEntered dhHeader">Entered By</div>
      </div>
      
      <div class="dataRow" rowid="123">
         <div class="dhDate">06/24/2009 09:20 AM</div>
         <div class="dhProvider">ECSD - BRATT VPK</div>
         <div class="dhEntered">Hoff, Linda</div>
         <div class="dvView">View</div>
      </div>
      
      <div class="dataRow" rowid="234">
         <div class="dhDate">06/23/2009 09:35 AM</div>
         <div class="dhProvider">CORRY STATION CHILD DEVELOPMENT (NTTC)</div>
         <div class="dhEntered">Hoff, Linda</div>
         <div class="dvView">View</div>
      </div>
      
      <div class="dataRow" rowid="345">
         <div class="dhDate">06/23/2009 09:25 AM</div>
         <div class="dhProvider">ECSD - PINE MEADOW VPK</div>
         <div class="dhEntered">Hoff, Linda</div>
         <div class="dvView">View</div>
      </div>
      
      <div class="dataRow" rowid="456">
         <div class="dhDate">06/17/2009 10:00 AM</div>
         <div class="dhProvider">ECSD - HOLM VPK</div>
         <div class="dhEntered">Hoff, Linda</div>
         <div class="dvView">View</div>
      </div>
   </div>
</div>

</body>


Points of interest:
  • As you can see, there is literally no look, feel or behavior in this layout. It can be easily generated by machine, and is also perfectly structure for an AJAX type site, where we replace certain components (like the search caption, params, data area) pretty much at will.
  • I've gone over the top here in terms of behavior abstraction - I'm not even calling out <a href> for the navigation links. That decision was based on the notion that this is some kind of back office or internal app and does not need to be attractive to spiders. Although the content here will be very attractive to spiders, not having good ol'fashioned links is a bad plan for any kind of production website where you want to gain SEO traction.
  • I've sort of hinted that there'll be other parameter blocks, based on the selection of top menu item - I think that was the original designer's intention.
  • I've sort of hinted that there will be other navigation pieces, since we see "1 of 9" and Next, we can assume there will be a "Prev" once the user has selected the next page. Although I show the direction I'd go there I probably won't fully flesh that piece out.

Next step, the look.
« Last Edit: September 12, 2011, 08:40:57 AM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #2 on: September 11, 2011, 01:13:40 PM »

The first thing I'd do if I were an orderly sort of guy, would be to add references to the top of the HTML for everything that I know I'll need to be styling. Note that there are other pieces out in the HTML that I'm not naming here, that's because I'll use their class or ID for locating them and animation more than styling. Since this is off the cuff I'll probably have to modify as I go on, but here we go for now:

<edit:>I don't have the bandwidth here to describe all the CSS selectors, much less the CSS3 selectors. Suffice to say that you can identify an element by using it's ID with the #(itemID) or it's class (.itemClass) or elements like "table" or "body" or "hr" are entered without anything in front of them. So saying I want to style the body I'd simply say, "body { stying }, styling items that have a class of "demo1" would be ".demo1 { }" and styling a particular element by ID would be "#contentArea" for example. CSS3 selectors are REALLY powerful and are also the basis for jQuery's power. IT is strongly recommended that if you do not understand CSS selectors you take a bit of time to look those up and understand them in concert with this tutorial.</edit>


<html>
<head>

<style>
.menu { }
.menuItem { }
#contentArea { }
#searchBlock { }
#searchCaption { }
#searchParams { }
.paramRow { }
.paramCaption { }
.paramList { }
#dataBlock { }
#dataNav { }
.dataHeader { }
.dhHeader { }
.dhDate { }
.dhProvider { }
.dhEntered { }
</style>

</head>
<body>

...


So you can see we've added a style section to the top of the page. I've added a style reference for each element that I think I'll need to reference. Now: This is NOT THE WAY I recommend things be done. We're doing it this way because Phae's test specifically asked for the styling to be "inline" and they described "inline" as at the top of the HTML document itself, rather than what we all consider inline as <div style="font-size: 12px;">Text<div>. Ergo, they're boneheads. But I digress. IMO styling should be kept in a separate file that can be modified by the style/look/feel team rather than by the structural delivery team (the PHP team delivering the actual structural data). This would look something like this:


<head>

<link rel="stylesheet" type="text/css" media="screen,handheld,projection,tv" href="/css/us-styles.css" />
<link rel="stylesheet" type="text/css" media="print" href="/css/us-print.css" />
<link rel="stylesheet" type="text/css" media="aural,braille,embossed" href="/css/us-aural.css" />

</head>
<body>...


This will then load the CSS files referred to here prior to rendering the page. Note also, that for the most clever of readers you can see a hint here about how I execute "cloaking in plain site" and how I can get a *lot* more spider friendly content on a page than I necessarily want a surfer to see.

Now that we have the essential structure for styling we'll being tackling individual elements.
« Last Edit: September 12, 2011, 08:41:34 AM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #3 on: September 11, 2011, 01:32:32 PM »

Grabbing the image and pulling it up into Photoshop I can sample the colors, which I'll use now. Note also that I'm just approximating the margins and padding by eye, I did not test this for ultimate accuracy:
<style>
.menu {
   margin: 5px 0 20px 0;
   padding: 5px 0 5px 20px;
   background-color: #607e1a;
   border-style: solid;
   border-width: 1px 0 1px 0;
   border-color: #415d05;
}

.menuItem {
   float: left;
   color: white;
   font-size: 14px;
   font-weight: bold;
   font-family: arial;
   margin-right: 20px;
}

...


Let's analyze:


Looking at the template, we can see that the menu extends from the complete left to the complete right of the viewport. There's about 5-10px worth of space on top. Theres a background color (#607e1a) and a border on the top and bottom (#415d05). There's some nice airy space in the menu area around the words. So looking at the stylization above, I've called out a margin of 5, 0, 20, 0 px - the margin style allows me to put all 4 margins in one line clockwise starting with Top. I could also have used margin-top: and margin-right etc, but this is more efficient. So I've got a 5px margin on top, 0 on the right, 20 on the bottom and 0 on the left. Note that I put px after numbers because I am specifically calling out pixels as my measurement - I could have used em, pt and others, but pixels make the most sense. When I use 0 (zero) as a value, I do not need to use a measurements because 0 is always zero. Margin is OUTSIDE of the box spacing.

The next item is padding, which is inside the box. Here you can see I've called out 5px on top, nothing on the right, 5 on the bottom and 20 on the left, which should position my first menu item (Home) correctly.

Now for coloring: I ask for the background color to be #607e1a and the border to be 415d05. Note that I've called out a solid border that only appears on the top and bottom. A very simple old-school technique for creating a semblance of 3D was to use 1px 2px 2px 1px as a border. I still do that to this day as a quick trick.

Inside the menu box I've asked for text to be white, Arial bold 14px. I could have put this right into the menu styling, since the "Cascading" part of CSS would have made the menu's children (menu Items) take on those properties. But I don't know if I'll want to specifically change the menu or anything later, so I did it this way.

The most interesting part of the menuItems is float: left. This says that DIVs no longer take up the entire horizontal space of the containing area, but get as small as they can and then "stack" on the left. I've put in a margin of 20px to the right of each div to give me the nice space between each menu item. Note that I could also have done a margin-left and then not added the 20px padding to the menu, this again was just a matter of quick choice.

There's something missing though: these are to be menu items and I want them to look like actuary elements. So I'll add a little something:


.menuItem {
   float: left;
   color: white;
   font-size: 14px;
   font-weight: bold;
   font-family: arial;
   margin-right: 20px;
   cursor:pointer;
}


Ah ha! Now when our mouse rolls over each item the cursor changes to a pointer, as if it's a link. But I want even more - I want the menu items to "underline" when I roll over them. This means that I need a specific style for an action, and the pseudo-modifier :HOVER does the trick. So I add a new element to my style descriptors:



.menuItem {
   float: left;
   color: white;
   font-size: 14px;
   font-weight: bold;
   font-family: arial;
   margin-right: 20px;
   cursor:pointer;
}
.menuItem:HOVER {
   text-decoration: underline;
}


It could be argued that this is behavior rather than look, but I'll not go there. Personally I think that it's still look because, although it changes when you roll over, it doesn't really do anything at all and is still in the providence of the look/feel team. Note that this pseudo-class (:HOVER) can really do anything at all. Bold the font, move things about, change the background color, you name it. It is now up to the look designer to decide how he wants to tell the user that "You can do something if you click here." Note that if you did a background color, you'd have an asymmetrical look - with the margin and padding it might not show up correctly. Therefore, it might be better to have the padding and margins defined by the individual menu elements, rather than the menu div itself. So I change things to this:


.menu {
   margin: 5px 0 20px 0;
   background-color: #607e1a;
   border-style: solid;
   border-width: 1px 0 1px 0;
   border-color: #415d05;
}

.menuItem {
   color: white;
   font-size: 14px;
   font-weight: bold;
   font-family: arial;
   height: 24px;
   line-height: 24px;
   padding: 0 5px 0 5px;
   cursor: pointer;
}

.menuItem:HOVER {
   background-color: #415d05;
}


Now the menu has margins for it's outside area, but does not define inside padding. The menu items have a height of 24px and a line-height of 24px - this is a trick to vertically center the text - and padding of 5px on both left and right. Now when the :HOVER class is enacted, the menu item has a nice darker color boundary around it, showing the user clearly that "something happens when you click here."

« Last Edit: September 12, 2011, 08:42:08 AM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #4 on: September 11, 2011, 02:01:08 PM »

Now on to the parameter section.



Consider:
<style>
...

body {
   background-color: white;
   font-family: arial;
   margin: 0;
}

...

#contentArea { padding: 10px; }
#searchCaption { font-size: 18px; font-weight: bold; }
#searchParams { background-color: #d4e1c4; padding: 5px; border-style: solid; border-width: 1px; border-color: #a0a0a0; }
.paramRow { clear: both; height: 24px; line-height: 24px; }
.paramCaption { float: left; width: 100px; }
.paramList { float: left; }
#editStartDate, #editEndDate, #captionEndDate { float: left; }
#selectProvider { width: 400px; }
.paramButtons { float: left }

...

</style>


Note that I forgot about the BODY styling in earlier posts. So here I define the body as having a background color of white, the whole website should default to the Arial (sans-serif) family of fonts and there should be no margin between the content and the edge of the viewport. That's how I make sure the menu styling above touches the absolute left and absolute right of the window.

Up through paramList things like pretty straightforward, given the examples above. New difference at #editStartDate: here you can see that by separating items with a comma, I can list multiple items that will have the same styling. Later then, we can see how by giving the Search and Clear buttons the same class, we can style them together with a single style descriptor. Thinking ahead a little, you could see how one could compress a lot of these descriptors into much less script by using classes. Additionally, as we'll see in another post, an item does not need to have only one class - it may contain many. Therefore, we could do something really clever like this:

.floatLeft { float: left; margin-right: 20px; }
.dateInput { width: 100px; }


... then in the HTML ...
<input type="text" class="dateInput floatLeft">


Another interesting new item is width. Just about any element can have a width, but it will behave differently based on it's position on a page, element type, association to its parent, you name it. By default, the width style will do nothing to a DIV because, again by default, DIVs take up the entire horizontal area of their parental container. By saying float: left, we have said that the div will be as small as possible and stack to the left. By specifying a width, it will do the same, but each div will now be the same width, giving us the look of a table. Or in this case, simply a nice aligned set of parameters. Note in the paramRow line we do something a little different as well. Clear is a style that breaks off float stacking. In other words, each row will halt the stacking of floats to the left, so we get a new, clean line. Also, we can see that by defining the line height as well as the height of the paramRow our input elements will be vertically center-aligned with our text elements.
« Last Edit: September 12, 2011, 08:43:01 AM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #5 on: September 11, 2011, 02:32:28 PM »

Now the data. This should be really straight forward by now:



<style>
...

#dataBlock { border: 1px solid #a0a0a0; padding: 1px; }
#dataNav { background-color: #415d05; padding: 5px 0 5px 3px; color: white; font-weight: bold; }
.dataHeader { padding: 5px 0 5px 3px; background-color: #d4e1c4; color: black; }
.dhHeader { font-weight: bold; text-decoration: underline; }
.dhDate { float: left; width: 150px; }
.dhProvider { float: left; width: 400px; }
.dhEntered { float: left; width: 90px; }
.dhView { float: left; width: 50px; cursor: pointer; font-weight: bold; }
.dhView: HOVER { text-decoration: underline; }

...

</style>


Ah - but there's something different on dataBlock. This is called a CSS shorthand, much like padding and margins. This allows me to define a border in one fell swoop, rather than 3 lines.

Note that we're really taking advantage of float-stacking to create our table look now. By stacking to the left with fixed sizes, we have the same look as a table. But there is one trouble: the capability to float is bound to the size of the containing parent, so if the size of the viewport is too small (i.e., the user has 1204x768 and their browser window kind of small) then floats will actually move down on to the next line. The way to fix this is to make sure that the containing div is always large enough to handle the data:

#dataBlock { border: 1px solid #a0a0a0; padding: 1px; width: 700px; overflow: auto; }


What I did here was add up all the columns width, then added another 10px for good measure. Then added the overflow: auto style which is extremely cool: if the size of the DIV is larger than the viewport, it will automatically add scroll bars. This behavior is used to great affect for having more data on the screen than can be viewed at any moment. If we had left the overflow at it's default, the data divs would have stretched out over the border of our screen and gotten funky. This effect and resolution alone is worth quite a bit of time to analyze and grok.

Note that I have not colorized the alternating lines: we will be doing that programmatically in a future post.

I've also made the dhView column look different in preparation for "doing something" when the user clicks on it.
« Last Edit: September 12, 2011, 08:43:31 AM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #6 on: September 11, 2011, 02:43:10 PM »

In the second post I showed what the ultimate intention of the HTML is, but if that's what is spit out of the server, then the server is doing all the work all the time, and the page is essentially dead. What we want is a framework for pushing data into, rather than a completed piece. So I propose a different actual HTML framework:
<body>
<header><navigation>
<div class="menu">
   <div class="menuItem" ref="home">Home</div>
   <div class="menuItem" ref="providers">Providers</div>
   <div class="menuItem" ref="practitioners">Practitioners</div>
   <div class="menuItem" ref="children">Children</div>
   <div class="menuItem" ref="reports">Reports</div>
   <div class="menuItem" ref="options">List Options</div>
   <div class="menuItem" ref="users">Users</div>
</div>
</navigation></header>

<div id="contentArea">
   <div id="searchBlock">
      <div id="searchCaption"></div>
      <div id="searchParams">
      </div>
   </div>
   
   <div id="dataBlock">
      <div id="dataNav">
         <div id="dataLocation">Page: 0 of 0</div>
         <div id="dataGoTo">
         </div>
      </div>
   </div>
</div>

</body>
</html>


There are about a bazillion ways this can be done, so I've made a few choices here for expediency:
  • I've hinted that the menus will always be in view and will always be the same. This is not a good plan for a real application. You may wish to have a page without the menu, or a different menu, or simply grand different menu items to different users with different roles. But I'll leave that up to you to imagine.
  • I've hinted that the search and search parameters are always available in one way or another. Bad plan from a larger perspective because this limits what we think the scope of the application will be.
  • I've hinted that the dataNav area will always be visible and always contain roughly the same data. Again, bad plan from a larger perspective.

Alright, caveats out of the way, let's get to work.
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #7 on: September 11, 2011, 02:57:12 PM »

First step - using Javascript in our demo.

Again, the "inline" notion means that we'll be putting this stuff at the top of the page. This is a BAD PLAN. Just like CSS, it should be contained in a separate file so that the behavior team can work it without dicking with anyone else. Additionally, I strongly recommend that people look at the minify project at Google, or other equally excellent ways of reducing the total size of javascript and CSS so that the load time of pages is fast and the load against the server is reduced.

So the right way to do things is this:
<html>
<head>

<script src="/js/siteScript.js"></script>

</head>
<body
...


... but for this demo and Phae's needs we'll put the script right up into the top of the page. So we modify our HTML file to include this:
<html>
<head>

<script>

</script>

...

</head>
<body>

...

</html>


And with that, we have our working area to add code to our page. We're going to be adding code to the header that activates at different times: we're going to do some that executes the moment the document is ready to be rendered for the user (when all resources have been pulled down and size-identifed) and code that will activate based on events (like clicks) on the page.

The notion for our code structure is called "unobtrusive scripting." Rather than the oldest of old-school mechanisms for firing off an event:
<input type="button" value="Go!" onClick="doSomething()">


We are going to "hook" elements in our HTML structure and bind actions to them. Once again, this allows our structural and PHP server team deliver the basics, our look and feel team the ability to change the look at will without affecting our ability to modify the actuary behavior of the page.

Lastly, we're also going to do some styling that is dynamic rather than static to begin to tease about how jQuery can really raise the bar on our page look and our ability to rapidly produce sites.
« Last Edit: September 12, 2011, 08:44:12 AM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #8 on: September 11, 2011, 03:35:15 PM »

Here we need a little assistance. There are ways of doing this with the natural onLoad event fired against the body (or most elements, to be fair) but when using the native DOM and browser functions we get into a tailspin of having to deal with idiosyncrasies of each browser, rendering mechanism and event model. And believe me - you really don't want to do it. It's such a gawdawful PIA that it has driven more than one webmaster to drink.

So we're going to employ jQuery, a high performance framework for manipulating the DOM (++). There are several things out there like jQuery - I've become quite enamored with it so I'll use it here. But fair enough, there are LOADS of ways you can do the things I'll describe here.

First step: we need the jQuery library. My recommendation is to simply call for it from Google. You can download it and server it yourself, but this is really easy. It is also my personal thought that pulling a couple strategic libraries from Google hints to them that there's a site out there worthy of their scrapers. Take from that what you will.

So, we add to the top of our page:
<html>
<head>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js"></script>


Here I've asked for both the jQuery minified library and the jQuery UI library. jQuery provides the mechanical guts of the system, which is both extremely powerful and standalone. It does not, however, add anything visual - it is all low level tools. So I recommend pulling the UI library as well, because once you see what it's got it will really help you out with animation, navigation, HTML5 style sites, site performance and site development speed. Also, there are about a bazillion plug ins for jQuery and the jQuery UI library that make adding some really spectacular effects to your site pretty easy.

THIS IS IMPORTANT: You're going to see a new syntax here, where the $ is used all the time and looks creepy. This is a Javascript shorthand. The $ can be assigned to any function of your choice to make your life easier. By default, most people now assume the $ to be "jQuery" - so doing this $('<div>'); is the same as this: jQuery('<div>');

I'm also not going to go over all the intricacies and capabilities of jQuery here - I personally have 4 paper books, 3 virtual books and several websites on speed dial because I use it like crazy and have not committed the entire thing to memory (alas, I never intend to). So you would be well advised to take this teensy tutorial and use it as a springboard for your own research on how jQuery works. It's worth your time, I promise.

So: Code we want executed when the document is ready:

<script>
$(document).ready( function() {
   alert('Hello World!');
});
</script>


This could also be seen like this:


<script>
$(document).ready(helloFunc);

function helloFunc()
{
    alert('Hello World!');
}
</script>


In the first instance, we are doing an "anonymous function." This means functional code that is bound to the document.ready event, but does not require a name. You'll see a lot of this as you research. The second example is the easier to read but somewhat less efficient procedural model - the name, "helloFunc" is passed to the ready function as the handler that should be called when the document.ready event is fired. Both work. I recommend the first because it keeps a cleaner name space.

The document.ready event is fired when the DOM has been built. All resources have been size-identified and are ready to render, but the page is not visible yet (although sometimes the page IS shown for a brief flash at this moment before your code is called). This is the perfect moment to bind events to elements on our page. IMPORTANT: Here's where we start moving away from full examples, as I will not be writing this entire page as a functional system, but hinting at the ways that we animate it. I am open to discussing these elements in future posts here though.


<script>
$(document).ready( function() {
   $('.menuItem').each( function() {
      var obj = this;
      $(this).click( function() { menuHandler(obj.attr('ref')); });
   })
});

function menuHandler(reference)
{
   alert('Do something for menu item ' + reference);
}
</script>


Wowholyshit that looks creepy. Here's the deal:
  • jQuery: when the document is ready, I want to do something. It's an anonymous function, and here comes the code.
  • jQuery: Find all elements on the web page that have menuItem in their classes. For each one, I want you to do something. Here comes the code.
  • I want the variable "obj" to be assigned to the this value - this is a keyword for the element that jQuery is reference on (this) iteration. Unfortunately, (this) doesn't always work perfectly in javascript syntax because of scoping concerns, so I make it a variable (obj) here to clean that up. Further discussion here is beyond this tutorial.
  • Bind the click event to (this) object. So obviously, we're going to bind a click handler to every element on the page with the menuItem class. It's anonymous, here comes the code.
  • Call the function menuHandler, passing the value of the attribute "ref" from each element. So: for the Home div, we'll pass "home" - for the List Options menu item, we'll pass "options" . Check earlier posts if this is confusing.

The function menuHandler will now get called every time a user clicks on one of the menu items. What we do at that point is up to the animator of the site - go somewhere else, change the internal structure of the page, doesn't matter. We'd probably put a switch statement in the menuHandler function to decide which button was clicked and what behavior to activate.

Note that you could bind each menu item individually and save time with a switch. But this is somewhat less efficient and binds page HTML structure to our code. For example:
<script>
$(document).ready( function() {
   $('#menuHome').click(homeHandler);
   $('#menuProviders').click(providersHandler);
   $('#menuOptions').click(optionsHandler);
});
</script>


In my code, it doesn't matter if there are 1 or 500 different menu items, each one will be correctly vectored. Or, should you want a set of 3 menu items for (this person) and a set of 7 completely different items for (that person), the actuary code does not change. Take a moment to re-read this section, it's really important.

I now must quit for a while, needing to go run errands with PinkHat again. More as I get time, perhaps later tonight.
« Last Edit: September 12, 2011, 08:45:04 AM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
kurdt
Lifer
*****
Offline Offline

Posts: 1153


paha arkkitehti


View Profile
« Reply #9 on: September 13, 2011, 10:57:04 AM »

Code:
$('.menuItem').each( function(obj) {
   $(obj).click( function() { menuHandler(obj.attr('ref')); });
})

Why not just use each function's capability of passing the element?

Also one thing you need to remember with jQuery is that if you are updating your page those elements won't be triggered with simple $('.link').click(function(){}). You have to use either $.live() or $.delegate(). $.delegate() is way more efficient but it also requires you to specify a context.
« Last Edit: September 13, 2011, 10:58:41 AM by kurdt » Logged

I met god and he had nothing to say to me.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #10 on: September 13, 2011, 11:29:24 AM »

Why not just use each function's capability of passing the element?
Variable scope. I may be off here, but IME (obj) will work fine during assignment time but will be either out of scope, undefined or worse, MISassigned at event time. By making it a variable in this case it guarantees that scope will be correct at event execution time.

Also one thing you need to remember with jQuery is that if you are updating your page those elements won't be triggered with simple $('.link').click(function(){}). You have to use either $.live() or $.delegate(). $.delegate() is way more efficient but it also requires you to specify a context.
Spot on, I just hadn't gotten too deeply into the jQuery part yet. Was going to start simply with load() to demonstrate populating the page and then talk about live(). Rather than galloping straight down to the clitoris I was going to have a little more foreplay Wink
Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #11 on: September 13, 2011, 07:05:49 PM »

OK - don't have a lot of time, but let's do a bit. As mentioned above, I'm not going to do the whole page - and from here on, it's going to be spotty examples of things.

What I'm going to do now is throw an Ajax request up at the server, placing the received HTML into the dataArea and then colorize the lines. It is worth looking up [jQuery Ajax] to see the 5 essential ways you can get data from a server.We need to wear two hats now: client and server side. Starting with the client, Javascript will request the data from the server. The flat out easiest way to do this is with the load() function that works on a jQuery result set like this:
$('#targetDiv').load('/adir/getData.php');

Essentially: load the content from (this domain)/adir/getData.php into a div with the id of targetDiv. It's that simple. So consider this fragment that might be at the top of our page:


<script>
localCurrentRec = 1;
localNumRecs = 20;

$(document).ready( function() {
   refreshData();
});

function refreshData()
{
   // Note that by specifying an object with values as param 2, this will be thrown as a POST.
   // If I'd wanted to throw it as a GET I could either not send param 2 or send it as an
   // ampersand-delimited set of name/value pairs just like a normal URL.
   $('#dataArea').load('/ajax/getRecs.php', {currentRec: localCurrentRec, numRecs: localNumRecs}, handleNewRecs);
}

function handleNewRecs(e)
{
   // e is the event object and is always passed by jQuery. We don't need it here.
   // This function is called after the data has been placed into #dataArea. So I
   // can reference it, change it, do anything I want with it. In this case I'm going
   // to gray bar every other data row. Look at the demo above to get the
   // class names of items that I am about to affect if you're confused:
   $('.dataRow:odd').css('background-color', '#a0a0a0');
}

</script>



Back up at the server, let's write some quick PHP to handle this request:
<?php
// file: getData.php

$output = array();
$db = new dbConnection('127.0.0.1''username''password''mydatabase');
$db->query("select id, datestamp, provider, entered_by from sometable limit {$_POST['currentRec']}{$_POST['numRecs']}");
while (
$db->fetchAssoc())
{
	
$output[] = <<<HTML
<div class="dataRow" rowid="{$db->row['id']}">
	
<div class="dhDate">
{$db->row['datestamp']}</div>
	
<div class="dhProvider">
{$db->row['provider']}</div>
	
<div class="dhEntered">
{$db->row['entered_by']}</div>
	
<div class="dvView">View</div>
</div>
HTML;
}

die(
implode(chr(10), $output));
?>

I've purposely made this extremely simple and, frankly, hugely susceptible to folks coming after your database so DO NOT use code like this as is. As you can see, I'm using my database class to connect to MySQL, get a subset of rows, create some HTML with that and spit it back in a single string. Since the classes and styling have all been defined at the site and are live on the client, I don't need to worry about styling anymore, because this HTML fragment will be styled perfectly as soon as it's placed into the document.

Let's add a little something. Note the View column - obviously this was intended to do a detail view of the records. So let's modify our return handler to bind events to the View column.

function handleNewRecs(e)
{
   // e is the event object and is always passed by jQuery. We don't need it here.
   // This function is called after the data has been placed into #dataArea. So I
   // can reference it, change it, do anything I want with it. In this case I'm going
   // to gray bar every other data row. Look at the demo above to get the
   // class names of items that I am about to affect if you're confused:
   $('.dataRow').click(handleDetail).filter(':odd').css('background-color', '#c0c0c0');
}


Yep, that was it. Note that we are using the extremely cool chaining feature of Javascript and jQuery to simply add another thing we want done. Now I'm grabbing ALL rows and binding a click event to them that will vector to handleDetail, then I filter the result set with the custom :odd specifier that will give me every other element from the set, and only THOSE then will have their background color changed. But we do need the handler, so let's look at that:

function handleDetail(e)
{
   var id = $(e.srcElement).attr('rowid');
   alert('Display the data for rowid: ' + id);
}


As you can see, it doesn't take much code to get some really cool stuff going.

I did it very literally here. But Kurdt, above, points out that we should use the live() function. This is an extremely powerful feature of jQuery that binds elements on the fly, without you having to do anything about it. So, should we put this in our document.ready function:
$('.dataRow').live('click', handleDetail);


then when the data came back in from the server it would automatically be bound up with the click event. I'll leave that up to the reader to investigate, it's very cool.
« Last Edit: September 13, 2011, 07:09:20 PM by perkiset » Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
Phaėton
Lifer
*****
Offline Offline

Posts: 555


⎝⏠⏝⏠⎠


View Profile
« Reply #12 on: September 20, 2011, 08:08:58 AM »

I've purposely made this extremely simple and, frankly, hugely susceptible to folks coming after your database so DO NOT use code like this as is. As you can see, I'm using my database class to connect to MySQL

What is so sexy about my database and what does it do for whomever if they can get in?!?
Logged

When I was your age we used to walk to the TV to change the channel....  _̴ı̴̴̡̡̡ ̡͌l̡̡̡ ̡͌l̡*̡̡ ̴̡ı̴̴̡ ̡̡͡|̲̲̲͡͡͡ ̲▫̲͡ ̲̲̲͡͡π̲̲͡͡ ̲̲͡▫̲̲͡͡ ̲|̡̡̡ ̡ ̴̡ı̴̡̡
perkiset
Olde World Hacker
Administrator
Lifer
*****
Offline Offline

Posts: 10096



View Profile
« Reply #13 on: September 20, 2011, 09:50:19 AM »

Less than just (your) database, anyone using that code as is would be susceptible to a SQL injection attack - so if there WAS something sexy, people could get at it.

Logged

It is now believed, that after having lived in one compound with 3 wives and never leaving the house for 5 years, Bin Laden called the U.S. Navy Seals himself.
Pages: [1]
  Print  
 
Jump to:  

Perkiset's Place Home   Best of The Cache   phpMyIDE: MySQL Stored Procedures, Functions & Triggers
Politics @ Perkiset's   Pinkhat's Perspective   
cache
mart
coder
programmers
ajax
php
javascript
Powered by MySQL Powered by PHP Powered by SMF 1.1.2 | SMF © 2006-2007, Simple Machines LLC
Seo4Smf v0.2 © Webmaster's Talks


Valid XHTML 1.0! Valid CSS!