Sunday, March 20, 2011

Revising the Dashboard Design - Mixing Stretch and Flowing Layout

This blog is in relation to the Visual Design Demo for the Dashboard.

Upon applying the Dashboard design in one of our projects, which utilizes CRUD transaction as well. The main limitation that was hindering us was how the height of the panelBoxes are limited based on the declared row height in the dashboard. When this  might be tricky since in some scenarios, I would want some items to be higher such as flowing items for form items and some that are stretched for tabular items.

Along with this sample and Andrejus's Blog on the Dynamic Dashboard (http://andrejusb.blogspot.com/2010/02/dynamic-dashboard-ui-shell.html), I am able to achieve this requirement by using a panelGroupLayout scroll to replace the dashboard.

Some of the limitations that I encountered with the default dashboard approach are the following.

  • Depending on the browser, the dashboard optimized render will sometimes fail to render the items correctly
  • Static Height issue
  • If the taskflow is using BackingBean bindings for the component, utilizing the same taskFlowBinding will make the other region not render at all
  • All taskflows will be activated the moment the page loads - I tried lazy loading the taskflows using the activate property but after 2nd activation, it just renders blank.

The main code which allowed me to render some items to flow and some to stretch is the following layout design.


And in case you're missing the part where it scrollToView to the moved item, that is handled by a little javascript to find the component to scroll to.


These combination allowed me to create a modified Dashboard Layout.


If you notice, the Employee PanelBox's height is depending on the amount of fields rendered in it compared to our Department table.

Note: If you need a copy of the full project design for the dynamic dashboard, just send me an email.

Sunday, March 13, 2011

Applied - #69 Code Corner - LOV Using Bounded TaskFlows

I guess to start my spring break blogging, I decided to do a proof of concept regarding the the #69 post in CodeCorner which strikingly is useful especially when your datasource does not rely on a direct database connection.

This blog consists of:

  • WebService design based on BC4J
  • UI ClientProxy consumer that converts the WS objects to map objects for generic usage.
  • TaskFlow LOV Design
  • Consuming page that will use this custom LOV

In my example, I will be utilizing a WS that is driven by BC4J and was designed from WSDL (TOP-DOWN). Using adf wizard to build my webservice classes, I am utilizing a stateless BC4J to service my DepartmentLovService.

For now, this service composes of two operations:

  • FetchDepartments - Allows filter by Location, MaxFetchCount, and WildCard
  • ValidateDepartment - Validates a Department input which can be the name or the id and only checks for a single returned instance

Our query in our ReadOnlyViewObject looks like this.


Pretty much the XSD request are the bindVariables and the response is a DepartmentType with an Id and a Name. That pretty much sets our WebService and using JDeveloper Wizard to create a WebService from WSDL, you should be all set by now.

Now for the Client side, we will still use JDeveloper to create a ClientProxy based on the same WSDL or better yet, the deployed WSDL. By now, on the client side i have 3 static methods.

  • Retrieve a Map of Departments - public static List<Map> retrieveDepartments(Integer fetchCount, String wildCard, BigInteger locationId, BigInteger includedDepartmentId)
  • Check if a departmentId is valid - public static Boolean isDepartmentValid(Integer departmentId)
  • Retrieve the Department information based on the department Id. - public static Map retrieveValidDepartment(Integer departmentId)

All these methods we will use later in our TaskFlow LOV.

We have two taskFlows, one is where our main form is which uses the LOV and one for the LOV taskflow itself. Our main taskFlow is pretty straight forward.



Take note how the button for my LOV is set to immediate. This way, when we consider the input as invalid, we can skip the validation phase so that we can refresh it correctly.

Now for the LOV taskFlow.



We use a pageFlowScope Bean to give us the list of Map which populates the table, and this will also hold all the necessary operations we'll need.


This method's constructor tries to inspect if a departmentId was submitted. This submitted departmentId will be considered as already selected thus we'd like to give the user the feeling that his old selection is still active. Besides that, we also want to filter the fetch count of our WebService. In a real environment, our LOV might contain give or take 300 options, but this will  be such an expensive WS call, so right now we're limiting it by saying "Fetch the first 10 records by default, but also include the record which I've already selected."

Our return selection is triggered when we hit the Ok button in our LOV confirming our new choice. All it does is retrieve the selectedIndex from the table and retrieve this same index from our map as well as set it as our returnParameter (Defined in the taskFlow structure).

Let's go back now to our main calling page and check the returnListener implementation as well as the validation.


This viewBean allows me direct access to my components and input, but even when using the pageDef as binding attributes, you should be able to achieve the same thing.

Return Listener
Let me start explaining the ReturnListener. This return listener tries to inspect the returnParmeters (Map) for return values matching the static key Strings I defined in our LovPageFlowBean. If a value exist, meaning an "OK" was called from the popup instead of a "CANCEL", we are going to first reset the value in the inputComponent using resetValue() this will guarantee that we tell ADF that if the component is invalid, reset it as we are going to set the correct values. After that a partial refresh is called.

Validator
At my first attempt, i was trying to mix the validator and the valueChange as I want to set the dependent field for the departmentName to be updated if the ID being validated is indeed valid. But for a much cleaner separation of the validation and the fetch for additional input, I decided to separate it. All the validator does is call the validate webservice operation, which is a really quick operation checking for atleast a row matching in the WS Side (See query). So all we're doing here is send the ID through the WebService, and websevice responds with a Nay or Yay hehehe.

ValueChangeEvent
So why bother with changeEvent? Because i want to set the outputLabel to show the selected Department when a department is selected from the LoV as well as when I enter a valid department Id.

Notes:
Why didn't I just use one WebService (Fetch) to handle everything?
- I use the fetch operation as my initial entry point of populating my table as well as when the user does a search (wildcard) in the LoV, I would do another re-fetch. Reusing the same WS for the validator might be expensive as this WebService functionality is deliver information while the validator should really be fast and light since it will constantly be called by the lifecycle to ensure all the data i'm sending to the server is valid for processing.

So here's the app demo. Enjoy.



Filter and select value

Select another value but when the initial search is done, always include what's already selected.

There is no department registered in the HR schema with ID set to 5

Set a valid value, and valueChangeListener sets the DepartmentName for you.

Saturday, March 5, 2011

Cascading Dropdown List from Bean

I'll demonstrate how to build a dropdown list where the values are coming from your manage bean. A good useCase for this scenario is when you can't use a BC driven LOVModel and pretty much rely on a manage bean to build your list. In my example, i'm relying on a webservice to return me the list of possible dropdown items which i'll need based on a submitted locationId. On top of it, i keep this list in a pageFlowScope map so that once I have already fetched it, i don't do a refetch especially when i'm asking for the same location's departments.

For my sample, I have a table that contains items (generic) with a location Id. The HR schema has a table of Departments that can be filtered based on this locationId.

So the final running app looks like this.



And yes the departments are filtered based on the locaitonId. So now for the code.

PageFragment

BackingBean

PageFlowBean

A question was raised about how to refresh the list incase there was any dynamic change, the answer to that is to decrease the scope of the bean which holds our map.

Note:
retrieveDepartmentListFromDatasource(locationId) calls a webService to return a list of available departments.