29 November 2011

APEX: Make a report row clickable in Report

When you create a "Report with Form", there will be an icon in the report which allows you to navigate to  the form page. Only when the user clicks the icon this navigation will take place. For the current project, this was not what they wanted. They wanted to click on the row instead of just the icon. This can be simply implemented using jQuery.
For this example we are going to use a "Report with Form" and modify it as described below.
All of our pages in the application have a page alias, the Report page alias is "EMP001" and the Form page has an alias "EMP002".
The default behaviour will appear in the page like the below screenshot, the cursor will turn into a small hand only when you move your mouse over the icon.

But we want to achieve the following: moving the cursor over the whole row changes the cursor to a small hand  indicating that the whole row is clickable. And not only that, also that the whole row is in fact clickable.
To achieve this we would need to "move" (or copy) the anchor to row-level.

When you look at the generated HTML code, it will look something similar to this:
The highlighted line in the picture is the icon which is shown in the Report page (alias: EMP001). As you can see in the image, the anchor (the "a" tag) has an href attribute which contains all the information it needs to navigate to the Form page (alias: EMP002). Even the page alias is in there, and this is what we will use to select the correct href.
Because the page alias is in the anchor, we can use the jQuery selector to get the appropriate element

$('a[href*="EMP002"]')

This will result in an array of anchor elements which we want to manipulate. For each of the elements in the array we want to retrieve the href attribute. The href attribute, we will keep in a local variable named "lnk". Now the code will look like:
$('a[href*="EMP002"]').each(function(index) { 
    lnk = $(this).attr('href');

});


This variable with the href attribute is going to be place at row level as a "data-href". From the current element we need to move up to the row level (tr) and add the attribute.

   $(this).parent()
          .parent('tr')
    .attr('data-href', lnk)

To make it clickable, we also need to add a click event to the row. This is where jQuery really shows its power, we can "chain" the click event to our selector. The code will grow slightly to the following:

 $(this).parent()
          .parent('tr')
    .attr('data-href', lnk)
    .click(function(){
      window.location=$(this).attr('data-href');
    })

To give the user the feedback that the row is clickable, we need to change the cursor to a little hand. Again we chain the mouseover event to the selector

$(this).parent()
          .parent('tr')
    .attr('data-href', lnk)
    .click(function(){
      window.location=$(this).attr('data-href');
    })
    .mouseover(function(){
      $(this).css('cursor', 'pointer');
    })

And because we also want to change the cursor back to default when the user move the cursor away from the rows in the report, the mouseleave event is also required

   $(this).parent()
          .parent('tr')
    .attr('data-href', lnk)
    .click(function(){
      window.location=$(this).attr('data-href');
    })
    .mouseover(function(){
      $(this).css('cursor', 'pointer');
    })
    .mouseleave(function(){
      $(this).css('cursor', 'default');
    })
Now that the jQuery code is complete, we can add this to the page
Double click at page level to open the page properties, and paste the jQuery code in the section labelled "Execute when Page Loads" and we are all set.


When you run the page you will notice that the whole row is clickable.
Inspecting the HTML after we add all the jQuery code will show that there is an anchor at the row level now, just what we wanted.

To make copy the code for your own use, the completed jQuery code will look like this
$('a[href*="EMP002"]').each(function(index) {
   lnk = $(this).attr('href');
   $(this).parent()
          .parent('tr')
    .attr('data-href', lnk)
    .click(function(){
      window.location=$(this).attr('data-href');
    })
    .mouseover(function(){
      $(this).css('cursor', 'pointer');
    })
    .mouseleave(function(){
      $(this).css('cursor', 'default');
    })
});
And to see this in action you can find a demo on apex.oracle.com

30 comments:

  1. Very nice. See and learn jQuery in practice.

    What would be incredibly nice is also have the row hightlighted.
    Any idea how to incorporate that in the above solution?

    gr. Bart

    ReplyDelete
  2. Hi Bart,
    This is one way to highlight the row on when you move the mouse (which can be done with CSS):
    My report rows have a class attached called "highlight-row" (this can be seen in the screenshot of the generated HTML)
    At page level, place this CSS style in the section called HTML Header:

    <style type="text/css">
    tr.highlight-row:hover td
    {
    background-color: #d12421 !important;
    color: #ffffff;
    }
    </style>

    A better way is to place this CSS in the appropriate CSS file.

    Hope this helps.

    Alex

    ReplyDelete
    Replies
    1. Hi, Alex.

      I was searching the web for a way to highlight a row in a classical or Interactive report on my Apex 4.1 page and then stumbled across this post.

      I really like the way you clearly explained, step-by-step, how to use JQuery selectors to make an entire report row "clickable". That is so cool and useful.

      I also see your suggestion on how to highlight a row using css. I tried out your code and it works great.

      However, I need a way to keep the report row highlighted as users navigate to other regions on the same page. The highlighted row serves as "context" to tell users which row is the currently "active" row.

      Would you know how to accomplish this and, simultaneously, make this highlighted row "clickable".

      Thank you for any help.

      FYI: When I click the "Reply" link on this blog using IE9.x, nothing happens. I had to open the blog in Firefox 15.x in order to get this "Reply" dialogue box to appear.

      Thanks, again.

      Elie

      Delete
    2. Hi Elie,
      Thank you for your nice comments.
      Yes, it's possible to keep the highlighted row as context. See an example here: http://apex.oracle.com/pls/apex/f?p=47888:EMP09:0::NO::

      1) Create a hidden item to store the clicked EMPNO
      2) Add the following javascript code at page level:
      $(function(){
      clicked_empno = $("#P9_EMPNO").val(); $('a[href$="P9_EMPNO:'+clicked_empno+'"]').parent().parent().children().addClass('highlight-employee') ;
      });
      This will add css classes (named highlight-employee) to all elements for the value stored in the hidden item
      3) Add a CSS rule to do the actual highlighting: .highlight-employee{background-color: blue !important;}
      4) In the link (column level), set the value for the hidden item

      Well, IE... what can I say :)
      Alex

      Delete
    3. Wasn't sure if the steps above was enough information that I decided to write a short note about it: http://nuijten.blogspot.nl/2013/01/apex-highlight-record-in-report.html

      Delete
  3. Hi,
    Its a good post however i have two links that open different pages howcan i accomplish this. thanks

    ReplyDelete
    Replies
    1. Hi Anonymous,

      The big question is: how do want it to work? How do you decide which link to open?

      Alex

      Delete
  4. nice post...it's what I'm looking for...
    but when I applied it to my application, it didn't work...
    I copied the jQuery code, then put it in 'Execute when Page loads' field with FORM09 as my form page.but nothing happen...
    can u tell me where is my mistake?

    thanks....
    Zee

    ReplyDelete
    Replies
    1. It's is quite hard to comment on where you made a mistake without being able to look "over your shoulder". There are many possibilities causing it "not to work". When you use a modern browser you might want to look what is going on "behind the scenes". In Firefox or Chrome you can use F12 to detect any errors in the console window.
      Is this application in a place where I can access it, like on apex.oracle.com? If that is the case, you might drop me an email and I'm willing to take a look at the way you implemented it.

      Delete
    2. the problem is solved. :)
      I changed :
      $('a[href*="FORM09"]')
      with :
      $('a[href*="9"]')
      where 9 is the page number, not an alias...

      thank you...

      Zee

      Delete
  5. Hey!
    Great code and it works, until you use pagination to go to page 2 in your report.
    Any suggestions?

    Thanks in advance!

    Yvonne

    ReplyDelete
    Replies
    1. Ah yes, good point... this is what you can do (not saying it's the best way, but... )
      1) move the code that's in the "Execute when Page Load" section to the "Function and Global Variable Declaration" section
      2) before the code add: function rowClick(){
      3) after the code add: }
      With steps 2 and 3 you create a function which can be used (almost) everywhere.
      4) in the "Execute when Page Load" section add: rowClick();
      That's the name of the function created in steps 2 and 3
      5) add a Dynamic Action (Advanced type)
      Event: After Refresh
      Selection Type: Region
      Region: Employees
      True Action: Execute Javascript Code
      Code: rowClick();

      That should do it.

      Delete
    2. Not yet working :(

      We're working on it.
      Maybe it's because we use an Javascript call as our link..?
      $('a[href*="ShowDetail"]')

      Delete
    3. The jQuery that you post is the selector, not a link. This selector means: find me all anchors which have ShowDetail in the link somewhere. The way I used the selector is to find the page-alias (which would be ShowDetail in your case).

      I created a new page, as described in my earlier reply: http://apex.oracle.com/pls/apex/f?p=47888:10:330414103723501:::::
      check it out, using Firebug or Chrome..

      Delete
  6. This comment has been removed by the author.

    ReplyDelete
  7. Works like a charm.
    The only thing I needed to do was change the page-alias (EMP002)

    ReplyDelete
  8. Thanks for this post - over the past year I've ran all sorts of places with this as a starting point.

    ReplyDelete
  9. nice post. some more details for general use in older versions (3.2 or <4). place the final code in jQueries function block in page html header:

    (script block)
    $(function() { [source] }});
    (/script block)

    most important part about "EMP002" is that its not page alias nor region id, its a jQueries search string for the url content. if your "pencil" was linking to javascript:editLine(xxx), then use "editLine" as search keyword in source (or some other distinct value to separate your region from others). if you got some unique parameters - try using them as search keywords.

    last bit that is still missing - cant hide the "pencil" column. whatever I try, href content is not found by jQuery.

    ReplyDelete
    Replies
    1. added $(this).css('display', 'none'); as a last line in the "a" loop and its done.

      Delete
  10. The javascript stops working after using search on an interactive report. Any solution to this?

    ReplyDelete
    Replies
    1. Yes, the "Execute when Page Load" is not the right place to put the javascript... This will cause it to only execute when the page loads (hence the name :)). It would probably be better to execute the javascript after refresh of the report region.

      Delete
  11. Hi Alex

    I'm pretty new to Apex and I have to do the same thing: Make a report row clickable. Now, before the actual code there is this on your example:

    apex.jQuery( document ).ready( function() {
    (function(){apex.widget.report.init("R1698825128352646793",{"styleChecked":"#ccc","internalRegionId":"1698825128352646793"});})();

    I understand that the long number is the Page ID. But what about the other, like "styleChecked", "#ccc", "internalRegionId"? From where did you get them?

    Thanx
    Sara

    ReplyDelete
    Replies
    1. Hi Sara,
      Sorry for the late reply (vacation :))
      The long number in your code is the Region ID, not the page ID.

      I'm not sure where that came from, possibly because the application is using an "old" theme.
      You don't need that code for it to make the row clickable (just tried it out on apex.oracle.com).
      Are you using Page Aliases? And for navigation as well?

      Alex

      Delete
    2. Hi Alex,

      hope you had an amazing vacation..
      Well at first I tried your code from above, but somehow there was no reaction, then I went over your example using the Page source, where I saw this long number "Region ID" and I was wondering if this was my problem, but it wasn't. Yet I don't know what the problem there was, but I found another solution instead. I put the code in the "HTML Header" field. In the beginning this didn't work either, because the usual Javascript opening wasn't enough in Apex 5 (in Apex 4.2 it works well with that), I had to put another code before. It took me a while to figure that out, but now it works just fine.

      Thanx anyway for your answer, I appreciate it.
      Sara

      Delete
  12. P.s. I of course us Apex 5.0, but this shouldn't be the problem that it's not working..

    ReplyDelete
  13. Hi Alex, as usual a great post!
    The code works as expected but I have a apex.item.checkbox as the first column in my row and when checking this it also triggers the row-click, is there any way to exclude the checkbox or prevent the checking of the box also to trigger the row-click?
    kind regards Anders

    ReplyDelete
    Replies

    1. Found the solution my self.
      juast add .children('td:not(:first)') on the parent selection as below.

      $(this).parent()
      .parent('tr').children('td:not(:first)')

      cheers
      Anders

      Delete
  14. This comment has been removed by the author.

    ReplyDelete
  15. Hi Alex, please how can I access the steps to highlighting a report row without actually submitting the page? The highlighted row should be based on the value in a hidden page item. i can see you have a demo called KEEP HIGHLIGHTED 2 but I cannot see the steps you took to achieve that.

    Regards
    Trix

    ReplyDelete
  16. Hi Alex,
    Please how can I access the steps to highlighting a report row without actually submitting the page? The highlighted row should be based on the value in a hidden page item. i can see you have a demo called KEEP HIGHLIGHTED 2 but I cannot see the steps you took to achieve that.

    Regards
    Trix

    ReplyDelete