Wednesday, 2 January 2013

Email and Subscription IR Reports in Apex 4.2

There has been a problem for some time with regard to email and subscriptions of IR reports. Prior to Apex 4.2, the "from" address for these reports when sent by email has always be the same as the "to" address entered by the user. In other words, if the email report was being send to john.smith@yahoo.com, it would have the from address set to john_smith@yahoo.com.

Having the "from" address the same as the "to" address, often resulted in issues on mail servers. Some mail servers have policies set that do not allow external emails to come from an internal server address. Other times, mail servers will treat these sorts of a mails as junk or span and not direct them to the inbox. Further, it just looked weird!

Now, Apex 4.2 allows you to explicitly set the "from" address either at the instance level, or at the report level itself.

Navigate to a page that has an interactive report, and view the Report Attributes. Scroll down to Advanced Attributes. Here, you can specify the "Email From Address":


You can also set the from address at the application level.  In Application Builder, edit and application and click the Edit Application Properties button. Scroll down to the Properties section, here you will find a property where you can special the application's "from emal address."

Sometimes it is just the little things that make a big difference!

Tuesday, 1 January 2013

A Response to Responsive Design in Apex 4.2

I have been following with a lot of interest the discussions regarding implementing Responsive Design using Theme 25 in Apex 4.2.  In case you are out of the loop, Responsive Design has to do with building applications that are fully functional across many different devices with various "viewport" sizes from the small screens of smartphones to the largest desktop screens.

My journey begin by reading Shakeeb Rahman's blogs on Responsive design here. I downloaded the presentation slides and worked my way through them. To me, this was exciting stuff. I was beginning to explore new approaches to web applications and it was quite cool had it all worked. I then downloaded Apex 4..2 and began to play with them 25 to see how it all fit together.

Not being convinced I had all the tools and information I needed, I purchased the book Responsive Web Design with HTML5 and CSS3 by Ben Frain that you can find here. It is a really great book and leads you through the whole implementation of a practical Responsive web application. I learned a tremendous amout about HTML5 and CSS3 and how to enhance what theme 25 already tries to accomplish. I built a couple of good test applications that worked very well on various deI vices.

Now here is where my response comes in.....

I have a large application that is used by many concurrent users. And, as you might expect, I thought "hey, why not make it responsive?"  I set about to do just that. Not as simple as you might think. The big issue for me is that the application is primarily a series of real-time reports. Many of these reports are quite large and consist of up to fourteen columns. Some of the reports include drill-downs where the data is displayed on modal pages for ease of use and navigation. These reports simply are not suited for small screens - you can't avoid scrolling and the reports are almost useless in a small format. I just didn't make sense to try and make the application work all small viewports. Here is a case where it would be far more productive to have 2 separate user interaces, one for desktop and one for mobile (fully supported in Apex 4.2). The mobile application can present streamlined reports with only critical columns while the desktop version can support the full reports.

There is, of course, a greater cost to having two separate interfaces (one for mobile and one for desktop). You need to support both versions of the application. The logic may in some places be duplicated. You may need to maintain separate CSS files and so on. But, in my case, no other approcah seems to make sense. I am open to comments from others that may suggest I am wrong. After all, I am new at Responsive Design. Please do feel free to offer you own feedback.

I also did a bit of checking on my application. In Apex, you can monitor how your application is being accessed. You can monitor what OS is used and what browser. I found, dare I say it, over seventy percent of my users are accessing my application from IE (Yikes!!!!). This despite a message on the login page advising that the application is best used with Firefox. So, why spend oodles of development time (not to mention money) trying to make the application responsive.

I am not suggesting that we ought not to learn about and use Responsive Desgin. It has a clear role in making our applications future-proof. After all, more and more users today access websites via a device other than a desktop. What I am suggesting, however, is that creating "responsive" applications is but one approach. There are instances when it will be appropriate and instances where is simply won't achieve great results.

Perhaps the key lies in planning the design from the very start. If instread of simply following an approach and layout dictated by our client, or worse, by a graphic designer, we take the position from the start that it would be ideal to have a responsive application. In other words, we approach the whole project from a responsive point of view and try to desgin and build an application that can in fact be independent of the device on which it is viewed. To do this, you need to understand some of the concepts, techniques and tools involved in creating responsive web applications. There is no doubt this is the future. In my view, it is one more tool in our toolbox and not the solution to every situation. Thankfully, Apex 4.2 gives us a number of approaches to consider and to implement.


Friday, 19 August 2011

Enabling and Disabling Classic Report Columns

Sometimes a classic report with many columns takes up too much space on the screen. There are a number of options for dealing with this issue, but one that I like is to provide the user with the ability to turn on and off individual columns or groups of columns.

I have seen several different ways of providing this functionality. For instance,  Denes Kubicek has a solution in his sample application, but it does not handle column groups and is somewhat more awkward. So, for what it is worth, I thought I would share my solution.

First, I create a series of checkbox items representing the columns (or column groups) that I want to allow the user to "turn on and off."  I put these items in a hide and show region so that they are accessible but not necessarily displayed until the user wants to change the columns.



Next, I modify the report. I set the Conditional Display attributes of each column in order to reference the related checkbox.


In some cases, I have more than one column being controlled by a single checkbox. My report has several columns that display dates. I use a single "date" checkbox to turn off and on the entire group of columns.

Next, I create a dynamic action for each of the checkbox items. The dynamic action is triggered by the "Change" event of the checkbox.


There are two true actions. The first, Execute pl/sql Code simply serves to put the value of the checkbox item into session state.


The second action simply refreshes the region containing the classic report.

 You will need to repeat the above steps to create an dynamic action that will trigger on the change of each of the checkbox items.

 The result allows the user to quickly enable or disable columns. Due to the use of the dynamic actions, the report quickly responds to the user changes. You can set defaults for the checkbox items so that some of the columns will show on page load and others will wait for the user to select the column for display.





Friday, 29 July 2011

Minimizing IR Filters On Default Report

I had a requirement for an IR report that specified that the background colour of the rows be set to specific colours based on certain data values. To accomplish this the easiest way possible and to allow the user to "turn on" and "turn off" the colours, I created a series of IR filters.

Each filter is set to define the highlight colour based upon specified data:


The result is excellent. The rows are highlighted based on the specified criteria and the user can disable specific highlights if they wish. Obviously, these filters are saved as the default report.

But, my mother taught me to keep things clean and tidy. And, when you first open the report you are faced with a list of filters that you may or may not wish to alter. It makes the report screen rather busy and I wanted to temporarily hide the filters when the page first loads. Hmmmm - dynamic actions?

Here's the solution:

1.  Using the Advanced dynamic action wizard, create a new dynamic action and set the event to Page Load.


2.  Create a true action of type Execute Javascript Code.


3.  Enter the following for the javascript code:

/* Minimize IRR filters on page load*/
if( $('#apexir_CONTROLS_IMAGE').attr("src") == '/i/minus.gif') {
   gReport.toggle_controls($x('apexir_CONTROL_PANEL_CONTROL'));
}

And, that's it!  A result that even my mother would approve of - everything neat and tidy!


The users can still access the filters by clicking on the "plus" sign and can just as easily hide them again.

Wednesday, 27 July 2011

Expert Oracle Application Express

If you have not yet bought your copy of Expert Oracle Application Express -  what are you waiting for? I got my copy in the mail a couple of weeks ago and was thrilled to read it. I am one of those developers who tries to read everything I can on Apex to stay at the top of what I do. And, for me, this book is now a "must read" for anyoune who aspires to be an Apex professional.




This book is written by a collection of authors - most of whom you will know from the forum or from their blogs. What I liked most about the content is that there is a focus on detailed information that you won't find elsewhere. It is not a book for the beginner who knows little about Apex, but rather, is aimed at the professional developer who is keen to know more.

I have already put to use much of what I learned from the book. In particular, Dimitri Gielis's chapter on charts and Martin D'Souza's chapter on dynamic actions really helped to further my understanding on two key areas of importance in my current development. All of the other chapters were also fantastic.

So, if you want to go beyond the boundaries of the basic documentation and move into the world of advanced knowledge - this book is a great place to start. I highly recommend it.

Friday, 15 July 2011

Tooltips On Charts

If you don't know what a "tooltip" on a chart is, it is the little piece of text that pops up when you hover over a segment on the graph. In the Apex Chart Wizard, it is referred to as a hint. When you select the "Hints" checkbox in the wizard, the tooltips are enabled.

While tooltips are available through the Apex Chart Wizard, very little of their real functionality is made available to you directly by the wizard. For example, my customer wanted the following:

1.  A specific font and text colour for the tooltip.
2.  The tooltip needed to show both the value and the percentage of the total.

My first reaction was "that's not possible." But, a bit of research and effort determined that not only was it possible but that we can do all sorts of cool things with the tooltips.






Like everything in Apex charts, it is handled through the XML.  There is a tag for <tooltip_settings> and defines the tooltip functionality. Here is how my XML for the above tooltip looks:


<tooltip_settings enabled="true">
      <format><![CDATA[{%SeriesName}{enabled:False} -
           {%Value}{numDecimals:0,decimalSeparator:.,thousandsSeparator:\,} -
          {%YPercentOfTotal}{numDecimals:0}%]]>
      </format>
       <font family="Arial" size="10" color="#808080" />
      <position anchor="Float" valign="Top" padding="10" />
</tooltip_settings>

As you can see, within the <tooltip_settings> tag there are a number of other tags such as <format>, <font> and <position>. There are also other tags as well that I have not used here.

The format section specifies what information will appear in the tooltip and how it will be formatted. The values in the tooltip are specified by keywords (they have a % in front of them). Here is the information in my tooltip and below are the keywords associated with them:

Air     -               4              -  57%
%SeriesName    %Value        %YPercentOfToal

Typically, Apex will insert the %Value keyword for you when you specify Hints in the Wizard. But that is rather limited. There are a large number of keywords you can use to show other values. For example, I have used %YPercentOfTotal which displays the percentage of the total bar represented by %Value amount. Take a look at some of the cool keywords available to you:

%YPercentOfCategory - the percentage of all the points with the same name
%YPercentOfSeries      - the percentage of the series represented by the point
%High                          - the high value of the point (candlestick)
%Low                          - the low value of the point (candlestick)
%Name                        - the name of the point
%Range                       - the range of the point
%YPercentOfTotal       - the percentage of all the series on the chart

After each keyword is the format definition for that keyword.  For example, {numDecimals:0} set the number of decimals displayed to zero. If you want no formatting at all, you can use {enabled:False} immediately after the keyword.

While the wizard in Apex will get you started, by using "custom XML" for your chart, you can have complete control of the tooltips and make them even more meaningful for your users. Try it out for yourself.

Here is a reference that will assist you in unlocking the power ot tooltips:

Tooltip settings and formatting

Friday, 8 July 2011

Custom Apex Maps - step by step

The cool thing about receiving a complicated requirement is that you learn something new and it turns out to be pretty cool.

In an application I needed to be able to display ocean ports on a map along with the number of shipments shipped from that port. Here is what the map looked like once I was done:


Well, that sounds easy enough! However, the maps that come with AnyChart's anymap in Apex 4, know nothing about ocean ports. The map like the one above has cities in the map information but those cities are not located exactly where the ports are located, nor do they have the same name as the port. The image of the map is exactly as I want it, but I need a set of custom locations to display on the map.

Let's get started.....

I decided to start by creating a collection on my page that would get the information I require from the customer's shipping data. I need the list of ports and the number of shipments per port.  Here is my code to create the collection.

declare
    l_query   varchar2(4000);
begin
  
     IF apex_collection.collection_exists(p_collection_name=>'CHINAMAP') then

        APEX_COLLECTION.DELETE_COLLECTION(
           p_collection_name => 'CHINAMAP' );

     END IF;


    l_query := q'(select null LINK, )';
    l_query := l_query || q'(port_of_load LABEL, )';
    l_query := l_query || q'(count(shipment_id) SHIPMENTS )';
    l_query := l_query || q'(from shipping_rep_sum )';
    l_query := l_query || q'(where export_country = 'China' )';
    l_query := l_query || q'(and main_carriage = 'OCEAN' )';
    l_query := l_query || q'(group by port_of_load)';

    apex_collection.create_collection_from_query (
        p_collection_name => 'CHINAMAP',
        p_query => l_query,
        p_generate_md5 => 'YES');
 
end;

And here is the resulting collection data:


If you were trying to display the above collection data on a map of China, it wouldn't work. The majority of the port names have no associated locations on the map.

Next I created a table that stores the longitude and latitude of the ports (I looked up these figures on the internet. The table data looks like this:


So far....so good. I've got my customer data, and I have the coordinates for the locations. Now, I need to be able to supply the map with the data in the right format. The map uses xml to plot the locations. I need to pass data to the map in a format that will look like this:

<data>
<series name="Ports" type="Marker" palette="Default" >
<point name="Ningbo" x="121.55" y="29.88" >
    <attributes>
       <attribute name="value1">23</attribute>
</attributes>
</point>
<point name="Qingdao" x="120.3575" y="36.093" >
    <attributes>
       <attribute name="value1">45</attribute>
</attributes>
</point>
<point name="Shekou" x="112.90" y="21.48" >
    <attributes>
       <attribute name="value1">2</attribute>
</attributes>
</point>
<point name="Nhava Sheva" x="72.97" y="18.95" >
    <attributes>
       <attribute name="value1">2</attribute>
</attributes>
</point>
<point name="Shanghai" x="121.375" y="31.254" >
    <attributes>
       <attribute name="value1">167</attribute>
</attributes>
</point>
<point name="Yantian" x="116.27" y="23.60" >
    <attributes>
       <attribute name="value1">3</attribute>
</attributes>
</point>
<point name="Hong Kong" x="119.17" y="25.27" >
    <attributes>
       <attribute name="value1">1</attribute>
</attributes>
</point>
</series>
</data>

I create a hidden text area on the page. In my case, I called it P6_XML_CHINA. Then I have an on load pl/sql process to generate the xml and populate the hidden item.  Here's my process code:
declare
    l_data      varchar2(4000);
    v_xlocation varchar2(50);
    v_ylocation varchar2(50);
    v_port      varchar2(100);

    cursor get_locations is select x_location
                                  ,y_location
                             from port_locations
                             where port_name = v_port;
begin
    l_data := '<data>'||chr(10);
    l_data := l_data ||'<series name='||chr(34)||'Ports'||chr(34)||' type='||chr(34)||'Marker'||chr(34)||' palette='||chr(34)||'Default'||chr(34)||' >'||chr(10);
  
 
     for c1 IN (select c002,c003
                from apex_collections
                where collection_name = 'CHINAMAP')


     loop
            v_port := c1.c002;
            v_xlocation  := null;
            v_ylocation  := null;
            open get_locations;
            fetch get_locations into v_xlocation, v_ylocation;
            close get_locations;

            if v_xlocation is not null
            then
               l_data := l_data ||'<point name='||chr(34)||c1.c002||chr(34)||' ';
               l_data := l_data ||'x='||chr(34)||v_xlocation||chr(34)||' ';
               l_data := l_data ||'y='||chr(34)||v_ylocation||chr(34)||' >'||chr(10);
               l_data := l_data ||'    <attributes>'||chr(10);
               l_data := l_data ||'       <attribute name='||chr(34)||'value1'||chr(34)||'>';
               l_data := l_data ||c1.c003||'</attribute>'||chr(10);
               l_data := l_data ||'</attributes>'||chr(10);
               l_data := l_data||'</point>'||chr(10);  

            end if;
          
      end loop;

      l_data := l_data ||'</series>'||chr(10);
      l_data := l_data ||'</data>';

       :p6_xml_china := l_data;

end;

Next, I create a map region and select a map of China. I set all of the map attributes the way I want them and apply the changes. I then edit the map and select the "map xml" tab and set "Use customer xml" to 'Yes'.  This displays the xml that the map will use. I need to edit the xml slightly.  Scroll down until you find the reference #DATA# and replace it with a reference to the hidden item with &P6_XML_CHART. (remember the period at the end). This will tell the map to use the xml stored in the hidden item which will plot all of the custom points.

You can plot anything on a map as long as you can supply the associated longitude and the latitude and prepare the required xml.

Customer map done!  Cool stuff learned!