Tyler Muth’s Blog

Technology with a focus on Oracle, Application Express and Linux

Posts Tagged ‘jquery’

jQuery Custom Selector

Posted by Tyler Muth on March 23, 2011

I’m working on a little Google Chrome Extension in my spare time to add a little formatting and bells and whistles to AWR Reports like converting Physical/Logical Reads/Consistent gets and bytes to KB/MB/GB. Also adding sorting and filtering to key tables, as well as making all wait events “hot” with a popup to show there definition, etc. Anyway, I found myself writing the same logic in a jQuery selectors all throughout my code to find the section headings of the report. Essentially, they’re either a p, h2, or h3 that contain text, have no child elements, and are a first-child of body. So, I wrote a custom selector to encapsulate the logic and drastically reduce and simplify my code:

jQuery.expr[':'].topLevelTextElement = function(element, index) {
     // if there is only one child, and it is a text node (<div>hello world</div>, not <div><span>hello world</span></div>)
     if (element.childNodes.length == 1 && element.firstChild.nodeType == 3) {
		// if it's parent is the <body> tag, ie it's not nested several levels deep
		if(element.parentNode.nodeName == 'BODY'){
			return jQuery.trim(element.innerHTML).length > 0;
		}
     }
     return false;
};

Here are some examples of it in action:

// iterate over each element the selector finds and log what type of node (tag) it is.
$(':topLevelTextElement').each(function(){console.log($(this).get(0).nodeName)});
//console output:
//h1
//h2
//h2
//p
//...

// iterate over each h2 element the selector finds and log the text it contains
$('h2:topLevelTextElement').each(function(){console.log($(this).text())});
//console output:
//Main Report
//More RAC Statistics
//Wait Events Statistics

On a related note, if you know JavaScript, CSS, and HTML, writing a Google Chrome Extension is REALLY easy. The documentation and examples are still a little weak. Integrating jQuery, jQuery Plugins, and jQuery UI was also quite easy, but there’s a minor catch for image references in CSS in that relative paths don’t work (easily). You have to use your extension name as an absolute path. I’ll blog about this later. If you need it now, just ask…

Posted in JavaScript / AJAX, jQuery | Tagged: | Leave a Comment »

jApex – A jQuery Plugin for APEX

Posted by Tyler Muth on August 19, 2009

In a previous post I proclaimed that jQuery Selectors Will Change Your Life.  While working on an AJAX centric APEX project, I wanted to use jQuery selectors to post data from an APEX page to an application process so I wrote a jQuery plugin. Over the course of this project the plugin has grown into something that I think the community would find useful.  Essentially it serves the same purpose as Carl Backstrom’s htmldb_get() function, but adds the power of jQuery selectors.  Carl was actually the one that introduced me to jQuery, and I’m sure he would have written something similar, only much better and in half the time.

I think the best way to introduce it is with a few quick examples.  I have a full set of working examples on apex.oracle.com here, but lets start with some simple examples to give you an idea of how it works.

APEX Items

The following code sends every item on an APEX page to the application process “SOME_APP_PROCESS”. It will then popup an alert with the results from the application process. Note that we did not have to specify each item individually, the jQuery selector (documented here) grabs them all.

var options = {
 appProcess: 'SOME_APP_PROCESS',
 pageItems: $(':input'),
 success:
   function(data){
     alert(data);
 }
};

$.jApex.ajax(options);

If we want to send all items inside a div with ID “employeeDiv” and send the results to the Firebug console:

var options = {
 appProcess: 'SOME_APP_PROCESS',
 pageItems: $('#employeeDiv :input'),
 success:
   function(data){
     console.log(data);
 }
};

$.jApex.ajax(options);

Want to send the items P1_NAME, P1_EMAIL, P1_PHONE?

var options = {
 appProcess: 'SOME_APP_PROCESS',
 pageItems: $('#P1_NAME, #P1_EMAIL, #P1_PHONE'),
 success:
   function(data){
   console.log(data);
 }
};

$.jApex.ajax(options);

Other Features

  • You can also send data to the x01-x10 parameters.  There are several examples of this in my sample app.
  • I had already written code to support sending arrays to the f01-f50 parameters used by Tabular Forms.  I really don’t like Tabular Forms and rarely, if ever use them.  However, I figured someone would want / request this functionality so I enhanced it a bit to better support Tabular Forms.  Keep in mind this functionality has not been tested much, so use at your own risk.

Tips

  • $ is the alias for jQuery
  • jQuery plugins almost always have 1 parameter that is object.  Each property of the object is analogous to a traditional JavaScript (or for that matter PL/SQL) parameter.
  • Parameters  can be objects, arrays, scalars or even functions.  Most people are used to scalars, so passing a function in as parameter / property can really be confusing at first.

Download

You can download the jQuery plugin here and the example APEX application here.

Update: I hosted the files in a more permanent location.

Posted in APEX, JavaScript / AJAX | Tagged: , , | 27 Comments »

jQuery Selectors Will Change Your Life

Posted by Tyler Muth on December 17, 2008

OK, maybe not your life but it will absolutely change the way you code JavaScript. If you haven’t used jQuery yet, here’s the description from the jQuery site:

jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript.

jQuery is technology agnostic, so you can use it in APEX, J2EE, PHP, .Net, Rails, etc. I’ve been using it with APEX for the last few months and there’s a pretty good chance it will actually be included in the 4.0 release of APEX.

Why are selectors so great? Because they completely change the way you work with JavaScript. Traditionally, people add JavaScript such as onClick() events in the code that renders a page. This is easy for hand-coded HTML or other bare-bones technologies such as PHP (when not using a framework). But in the case of frameworks such as APEX, you actually don’t have access to all of the code that rendered the page. Using selectors, you can get very granular access to any element on the page after it is rendered. For example, the following code changes the style of EVERY link on your page:

$(document).ready(function() {
  $("a").css('text-decoration','none');
});

Or maybe you want to add an onClick event to every div that has a class named “clickme”:

$(document).ready(function() {
    $("div[class=clickme]").click(function() {
       alert('Yep, you clicked me');
    });
});

The following code turns any div on the page red when you hover over it, then white when you move your mouse out of it.

$(document).ready(function() {
    $("div").hover(function() {
       $(this).css('background-color','#ff0000');
    },
        function() {
       $(this).css('background-color','#ffffff');
    });
});

Getting a little more APEX specific, here’s a bit of code that prints all values from the “SAL” column out to the Firebug Console (you must have Firebug installed):

// find all TD's with a class of t20data and headers=SAL.  For each of those, run some function.  console.log is Firebug specific.
$("td[class=t20data][headers=SAL]").each(function(){
  console.log($(this).html());
});

Building on the previous example again, lets change the color of the data in a column based on its value:

// find all TD's with a class of t20data and headers=SAL.  For each of those, run some function.  console.log is Firebug specific.
$("td[class=t20data][headers=SAL]").each(function(){
  sal = parseFloat($(this).html());
  if (sal<1000){
     theColor='green';}
  else if (sal >= 1000 && sal < 2500){
     theColor='yellow';
  }
  else{
       theColor='red';}
   $(this).css('color',theColor);
});&#91;/sourcecode&#93;

Lets continue to build on this example by changing the color of every cell in a row based on the value of the SAL column.  Notice that we walk up the DOM to the TR, then down the DOM to every TD in the row.

&#91;sourcecode language='javascript'&#93;
$("td&#91;class=t20data&#93;&#91;headers=SAL&#93;").each(function(){
 sal = parseFloat($(this).html());
 if (sal<1000){
 theColor='green';}
 else if (sal >= 1000 && sal < 2500){
 theColor='yellow';
 }
 else{
 theColor='red';}
 //$(this)  is currently the TD of the sal column.
 // Walk up to its parent TR, then down to all child TDs.  This effectively loops over every TD in a row
 $(this).parent('tr').children('td').each(function(){
 // $(this) is now the curent TD that is a child of the TR
 $(this).css('color',theColor);
 });
});&#91;/sourcecode&#93;

My final example if from a question on the APEX Forum (<a href="http://forums.oracle.com/forums/message.jspa?messageID=3178134" target="_blank">here's the thread</a>) where someone wanted to replace all instances of the APEX Datepicker item with the jQuery UI Datepicker (I posted about this control <a href="https://tylermuth.wordpress.com/2008/07/16/jquery-datepicker-and-apex/" target="_blank">here</a>).  In APEX 3.1 or greater (not 100% which versions) all datepickers are wrapped in '&lt;fieldset class="datepicker"...'.  This code looks for any of those items on page load and replaces them.

$(document).ready(function(){ 
    $('fieldset[class=datepicker]').find('img').css('display','none');

    $('fieldset[class=datepicker]').find('input[type=text]').datepicker({ 
             showOn: "both", 
             buttonImage: "http://ui.jquery.com/repository/demos_templates/images/calendar.gif", 
             buttonImageOnly: true}); 
}); 

Luis Cabrel pointed out that previous versions of APEX did not have the fieldset code and posted his solution in that same thread:

$(document).ready(function(){
    $('img[title=Calendar]').hide();

    $('img[title=Calendar]').parent().parent().
            find('input[type=text]').datepicker({
            closeAtTop: true,
            dateFormat: "dd-M-yy",
            showOn: "both",
            buttonImageOnly: false,
            duration: 'fast',
            firstDay: 1});
            });

Imagine how much time that would save you if you had even a couple of applications with 10-15 datepickers per app.

The Firefox plugin “Firebug” makes it so much easier to test and develop selectors since you can use HTML > Inspect to find the DOM nodes you want to select, then use the console to test them. console.log() is also infinitely easier to use for debugging than alert() since you don’t have to click “OK” for each event.

I simply can’t stress enough how useful jQuery selectors are. I strongly encourage everyone to take some time to explore them. There is a great tutorial called “Getting Started With jQuery” that goes into more detail. If you have other cool jQuery solutions with APEX, I’d love to see them!

Posted in Application Express, JavaScript / AJAX | Tagged: , , | 19 Comments »