One thing about OO implementing an MVC architecture in a stateless environment has eluded me. How does one cleanly manage interactions between the client and the server once the client has received its rendered HTML?
Consider this; I have a requirement in a current project to show several tables of data.
Data in these tables need to be sortable. When you click on a column header the data in the table will refresh and be sorted according to the data in the column.
The table of data also needs to be filterable. A filter could be applied to the data to show only rows where the last name starts with “H” or perhaps where some action is required.
Lastly the data displayed in the table needs to be nicely printable as a PDF or to FlashPaper. The resulting printed version would reflect the current state of the table showing only the filtered and sorted data.
An important consideration is that the data displayed in these tables will change throughout the application. For instance, in one case you might be viewing a table of users. Each user’s name might be a link to another page. Or, you might see a table of categories with each category having a checkbox you could select. (In this latter case the table would be shown in a form and some form action would deal with the selected categories.)
The point is that I want a generic system to flexibly create these storable, filterable, paginated tables.
Traditionally, I would probably just write some code that output a query into an HTML table. The output code would be one-off and written to let me do exactly what I need. So, if I needed a user’s name to be a link I’d simply surround it with a link tag. The column headers would be links back to the same page and would cause the server to rerun the query, but sorting it according to the selected columns. To filter data I’d have a form or links that would ultimately reload the page again to filter the data.
Because you can’t generate FlashPaper or PDFs directly from a browser (at least not using JavaScript), I would, when the user decided to print the table, once again, reload the page to rerun the query but this time have different display logic that would generate the PDF and send it to the user.
There’s nothing really wrong with this except that it’s repetitive, wasteful (in terms of network, CPU and database utilization), and rather procedural. There are many aspects of each of these tables that are repeated from table to table (the styles, the logic to output rows, the fact that the data can be filtered, the JavaScript to sort the data, the need for printing, the framework for making the requests to the server, and more).
Wouldn’t it be really nice to have something (a component or custom tag or JavaScript library?) which I could throw a set of data and configuration information at and have it be able to output a table that did exactly what I wanted?
One of the tenets of Object Oriented Programming is encapsulation. In a nutshell encapsulation means to hide your object’s implementation. Whatever uses your object shouldn’t care about how your object does its job, just that the job is done (and done correctly). So, with my tables of data, I want to encapsulate the process of creating the table and all the logic involved with sorting and filtering and printing it. I really only want to define what’s different between tables and have some other system automatically handle it.
What’s befuddling me is that the requirements genuinely requires interaction with the server from the client at least to print data.
In an effort to work through this problem let’s say that I temporarily forget that there is a requirement to view the table and pretend that I’m only working with data on the server. I could create a table component with an interface like this:
Table = init(data data, tableConfiguration Config) This would be a constructor for the Table. When constructed the table would receive a set of data and configuration settings. For now, I’m going to ignore the format of the data. You can imagine it’s a query or XML if that makes you feel better, but I don’t think it’s necessary yet. The configuration settings would probably specify column names in the table and the column’s datatype.
sort(iSort Sorter) This method on the Table component would receive an object that implemented an iSort interface (ok, in ColdFusion this would be convention and not a requirement). The iSort interface would probably define a method to compare items of data from the Table. The Table would know how to use the Sorter’s interface and would sort the data accordingly.
Here’s a pseudo code example to illustrate this:
<!--- create a table that holds data ---> <cfset Table = CreateObject("Component", "model.table.Table").init(data) /> <!--- create an alphabetical sorter to sort the data ---> <cfset Sorter = CreateObject("Component", "model.sort.alphaSort").init("lastName", "ascending") /> <!--- pass the sorter into the table ---> <cfset Table.setSort(Sorter) />
As of now the Table’s data would be sorted how I’d like it to be.
filter(iFilter Filter) As with the sort method, this would receive a Filter object that implemented an interface that the Table knew how to use to filter the data. The iFilter interface would probably have a method that checked if an item of data matched the filter or not.
I start running into problems when I begin thinking about how to create visual representations of the data. In other words, how the heck to I translate the data in the component to HTML?
Well, you could, in theory, write a custom tag that knew the Table’s interface and could read data out of the Table and convert it into an HTML table. The problem is that this “breaks” encapsulation. If a component exposes its internal data to an external object such as a tag, then that data isn’t really encapsulated. You might as well store it in a structure. So, I don’t really like the idea of a tag.
I could also add a Render method to the Table component. Ideally this method would return the HTML to display the component. I’m not sure how I feel about this because it feels like the Table is beginning to take on too many responsibilities, but this is more of a gut feeling. It seems to beat passing the component into a tag.
The other nice thing about a render method on the table is that I could also add a print method that called the render method and then translated the resulting HTML into PDF or FlashPaper format.
So far, this seems like a reasonable solution. However, how do I sort and filter data once the Table is rendered to HTML and the HTML is displayed in the user’s browser?
The only answer I have to this question is that I cache the Table on the server and require the user to make a second trip (which I already don’t like) to the server which will then resort the cached Table. I don’t like this because it feels like I no longer have one component, but a set of related systems. I have the Table itself, but the Table has to know what events or pages to call on the server to get resorted. The Table has knowledge outside itself. Encapsulation is broken.
This is where I start to think about implementing the Table in JavaScript. I could implement the same API I described above in JavaScript. All, that is, except for print. I’ve been unable to think of a clean way to have a print method on a JavaScript Table object.
I suppose a print method could accept a URL and that the print method could get the Table’s rendered HTML and submit it to the provided URL which would be required to return the PDF or FlashPaper data.
After all this writing, I actually like that idea! It might seem weird that the JavaScript is making a call to the server, but it IS encapsulated. The JavaScript Table has no knowledge of anything outside itself. It simply knows that it submits data to a URL passed into the print method.
What do you think? How would you tackle something like this?
Comments on: "I'm Stumped" (13)
Do you have the option of using Flex 2.0 or perhaps some ajax framework such as Adobe’s Spry? In Flex 2.0 you can create DataGrid objects that the user can sort and filter without having to go back to the server. Flex also has print capabilities. Spry also enables sorting and filtering without doing a page refresh.
Otherwise I think you are going to create alot of code that others have already written either in Flex 2.0 or in JavaScript-ajax.
LikeLike
I guess I should have been explicit. I really would LOVE to use Flex 2. However, that’s just not in the budget.
Now that I’ve said that, I do expect to use Spry for this system… but even then, I just wish I had one package I could wrap up and use. As it is, with Spry I’ll have to have a set of includes for the various scripts before I can use mine. I know I could wrap this up into a set of custom tags, but then creating the user interface for the filters becomes tricky (they can all have different interfaces, sadly).
All in all, nothing I’ve thought of yet has smelled right. (Except Flex, that is.)
LikeLike
Ray Camden has a set of custom tags he uses to do this sort of thing in Lighthouse Pro. It’s procedural and wasn’t designed to be used outside of that package, but it functions fairly well. It accepts a query and combines that with user input (filter params & column sort info) to display a nice sortable table. However, that’s not what you were asking.
I agree that an HTML solution needs to be devised. There are too many times when Flex isn’t an option. Personally, I think you’re adding unnecessary complexity and server load by asking for dynamically generated PDF/Flash Paper based on the current query. I would advocate using a custom Print Style Sheet that eliminated unwanted info and presented the data in a pleasing format for paper. It would take some planning, but it’s workable and puts the load on the client.
I’m slightly over my head here, but regarding the unwanted break in encapsulation, it might be best to break encapsulation with an API that would interface with a client tag/function specific to an output format. You could have the core function that would store the data and handle user input (filters/sorts), and then you could have a client, or plug-in function to render HTML, PDF/Flash Paper, XML, XLS, or other web services.
That way, when a new method of outputting the data is desired one would just need to write a new output plugin. Example, Person A might prefer to display the data using table tags, whereas Person B might want to try a fancy DIV tag layout, and Person C wants to output XML.
Just my .02
LikeLike
I assume by “not in the budget” you are referring to Flex Data Services. Why not use the free SDK with simple HTTP requests instead?
LikeLike
Hans – There’s multiple ways to look at “not in the budget”. Really, they don’t want to pay for my time to use the free SDK (nor for Flex builder). Also, the PCs the app will be running on will be running a modern browser, but they had issues previously with Flash on the client PCs being able to support Flash Video. For this reason requiring (and supporting) the latest version of the Flash Player is too expensive.
LikeLike
Hi Doug,
Keep an eye on my blog over next few weeks as I have worked up a generic approach to solving these problems as part of LightBase using UI components and certain controller and model conventions. I have the architecture figured, but don’t want to post too much until I have a chance to play with the (fairly simple) code and check everything out. If you want to email me offline about any specifics, feel free.
LikeLike
Doug ,I might be missing the point, but could you not use something like JSON to “render” the table data out to the client, you can then use client tools to sort and filter. These filters you store on the client as JS objects, that you can then send (as JSON objects again) and render it as a PDF, so, when you have a request to print a table as PDF you would send (from the client):
Original table (in JSON format)
Filter JSON object
Sort JSON object
you would then instantiate another table object (stateless right?) with this data, filters and sorters and do whatever you want for the PDF
Make sense?
LikeLike
Mark – To be totally honest, I don’t know much about JSON. I know enough to say that what you’re suggesting sounds logical. I’ll look into it further when I reach that point. Thanks.
LikeLike
Doug
JSon has a couple of functions for CF that serialise CFObjects into a Json object (its like, really simple xml, but it evals straight to a JS object)
This would mean that you would set up in Java Script a Table object, a sort and a filter object.
You would have to kind of replicate this on the client side with your sorting and filteing (lots of articles on this all the way round) and when a client has finished modifying their sort and filter, then you save those objects back into a form (json js library) and then post those back and create the stuff.
Contact me off list and I can help you out with some of this…
(gmail same as email ehre)
LikeLike
http://dotnet.org.za/members/glucophage-pi.aspx glucophage pi | glucophage pi
http://dotnet.org.za/members/methotrexate-use-in-placenta-accreta.aspx methotrexate use in placenta accreta | methotrexate use in placenta accreta
http://dotnet.org.za/members/3600mg-of-neurontin-a-day.aspx 3600mg of neurontin a day | 3600mg of neurontin a day
http://dotnet.org.za/members/augmentin-and-alcohol-use.aspx augmentin and alcohol use | augmentin and alcohol use
http://dotnet.org.za/members/z-pack-and-erythromycin-allergy.aspx z pack and erythromycin allergy | z pack and erythromycin allergy
http://dotnet.org.za/members/erosive-gastritis-and-methotrexate.aspx erosive gastritis and methotrexate | erosive gastritis and methotrexate
http://dotnet.org.za/members/levaquin-caused-digestive-illness.aspx levaquin caused digestive illness | levaquin caused digestive illness
http://dotnet.org.za/members/can-i-give-motrin-and-dimetapp-to-my-teen.aspx can i give motrin and dimetapp to my teen | can i give motrin and dimetapp to my teen
http://dotnet.org.za/members/how-to-snort-lidocaine.aspx how to snort lidocaine | how to snort lidocaine
http://dotnet.org.za/members/fosamax-jaw.aspx fosamax jaw | fosamax jaw
http://dotnet.org.za/members/long-term-usage-omeprazole.aspx long term usage omeprazole | long term usage omeprazole
http://dotnet.org.za/members/substitutes-for-fosamax.aspx substitutes for fosamax | substitutes for fosamax
http://dotnet.org.za/members/januvia-pros-and-cons.aspx januvia pros and cons | januvia pros and cons
http://dotnet.org.za/members/fosamax-and-low-velocity-long-bone-fractures.aspx fosamax and low velocity long bone fractures | fosamax and low velocity long bone fractures
http://dotnet.org.za/members/what-is-omeprazole-used-for.aspx what is omeprazole used for | what is omeprazole used for
http://dotnet.org.za/members/avandia-crushed-rogaine.aspx avandia crushed rogaine | avandia crushed rogaine
http://dotnet.org.za/members/erythromycin-antibiotic.aspx erythromycin antibiotic | erythromycin antibiotic
http://dotnet.org.za/members/namenda-and-strokes.aspx namenda and strokes | namenda and strokes
http://dotnet.org.za/members/medrol-pills-and-thrush.aspx medrol pills and thrush | medrol pills and thrush
http://dotnet.org.za/members/methotrexate-and-folic-acid.aspx methotrexate and folic acid | methotrexate and folic acid
http://dotnet.org.za/members/20-mg-omeprazole-delayed-release-100-tablets.aspx 20 mg omeprazole delayed release 100 tablets | 20 mg omeprazole delayed release 100 tablets
http://dotnet.org.za/members/side-effects-namenda-combination-aricept.aspx side effects namenda combination aricept | side effects namenda combination aricept
http://dotnet.org.za/members/best-time-to-dose-aricept.aspx best time to dose aricept | best time to dose aricept
http://dotnet.org.za/members/levaquin-side-effects.aspx levaquin side effects | levaquin side effects
http://dotnet.org.za/members/solu-medrol-msds.aspx solu medrol msds | solu medrol msds
http://dotnet.org.za/members/neurontin-medication.aspx neurontin medication | neurontin medication
http://dotnet.org.za/members/erythromycin-hydrochloride-msds.aspx erythromycin hydrochloride msds | erythromycin hydrochloride msds
http://dotnet.org.za/members/motrin-to-stop-bleeding.aspx motrin to stop bleeding | motrin to stop bleeding
http://dotnet.org.za/members/aricept-for-mini-stroke.aspx aricept for mini stroke | aricept for mini stroke
http://dotnet.org.za/members/can-you-take-motrin-if-getting-bloodwork-done.aspx can you take motrin if getting bloodwork done | can you take motrin if getting bloodwork done
LikeLike
http://dotnet.org.za/members/benzocaine-vs-lidocaine-for-pain.aspx benzocaine vs lidocaine for pain | benzocaine vs lidocaine for pain
http://dotnet.org.za/members/neurontin-300mg.aspx neurontin 300mg | neurontin 300mg
http://dotnet.org.za/members/can-tramadol-and-motrin-be-taken-together.aspx can tramadol and motrin be taken together | can tramadol and motrin be taken together
http://dotnet.org.za/members/avelox-and-alcohol.aspx avelox and alcohol | avelox and alcohol
http://dotnet.org.za/members/present-information-about-fosamax-google.aspx present information about fosamax google | present information about fosamax google
http://dotnet.org.za/members/augmentin-alcohol.aspx augmentin alcohol | augmentin alcohol
http://dotnet.org.za/members/naltrexone-prices.aspx naltrexone prices | naltrexone prices
http://dotnet.org.za/members/levaquin-500-mg.aspx levaquin 500 mg | levaquin 500 mg
http://dotnet.org.za/members/side-effects-of-depo-medrol-for-dogs.aspx side effects of depo medrol for dogs | side effects of depo medrol for dogs
http://dotnet.org.za/members/aricept-stopping-how-too.aspx aricept stopping how too | aricept stopping how too
http://dotnet.org.za/members/naltrexone-or-campral.aspx naltrexone or campral | naltrexone or campral
http://dotnet.org.za/members/penile-clamp-lidocaine.aspx penile clamp lidocaine | penile clamp lidocaine
http://dotnet.org.za/members/januvia-side-effects.aspx januvia side effects | januvia side effects
http://dotnet.org.za/members/reports-in-europe-of-januvia-use-with-insulin.aspx reports in europe of januvia use with insulin | reports in europe of januvia use with insulin
http://dotnet.org.za/members/stepped-on-nail-augmentin.aspx stepped on nail augmentin | stepped on nail augmentin
http://dotnet.org.za/members/fosamax-and-atrial-fibrillation.aspx fosamax and atrial fibrillation | fosamax and atrial fibrillation
http://dotnet.org.za/members/motrin-treatment-for-bed-wetting.aspx motrin treatment for bed wetting | motrin treatment for bed wetting
http://dotnet.org.za/members/neurontin-for-hot-flashes.aspx neurontin for hot flashes | neurontin for hot flashes
http://dotnet.org.za/members/methotrexate-toxicity.aspx methotrexate toxicity | methotrexate toxicity
http://dotnet.org.za/members/ok-to-take-motrin-if-having-chest-pains.aspx ok to take motrin if having chest pains | ok to take motrin if having chest pains
http://dotnet.org.za/members/naltrexone-ucla.aspx naltrexone ucla | naltrexone ucla
http://dotnet.org.za/members/neurontin-for-the-treatment-of-epidural-fibrosis.aspx neurontin for the treatment of epidural fibrosis | neurontin for the treatment of epidural fibrosis
http://dotnet.org.za/members/medrol.aspx medrol | medrol
http://dotnet.org.za/members/gf-augmentin.aspx gf augmentin | gf augmentin
http://dotnet.org.za/members/dental-work-methotrexate.aspx dental work methotrexate | dental work methotrexate
http://dotnet.org.za/members/lidocaine-ointment.aspx lidocaine ointment | lidocaine ointment
http://dotnet.org.za/members/motrin-active-ingredient.aspx motrin active ingredient | motrin active ingredient
http://dotnet.org.za/members/alzheimers-namenda-adverse.aspx alzheimers namenda adverse | alzheimers namenda adverse
http://dotnet.org.za/members/pinpoint-pupils-neurontin-methadone.aspx pinpoint pupils neurontin methadone | pinpoint pupils neurontin methadone
http://dotnet.org.za/members/how-long-does-glucophage-stay-in-system.aspx how long does glucophage stay in system | how long does glucophage stay in system
LikeLike
http://dotnet.org.za/members/20-mg-omeprazole-delayed-release-cheap.aspx 20 mg omeprazole delayed release cheap | 20 mg omeprazole delayed release cheap
http://dotnet.org.za/members/is-glyformin-the-same-as-glucophage.aspx is glyformin the same as glucophage | is glyformin the same as glucophage
http://dotnet.org.za/members/is-it-ok-to-drink-alcohol-while-taking-levaquin.aspx is it ok to drink alcohol while taking levaquin | is it ok to drink alcohol while taking levaquin
http://dotnet.org.za/members/acid-reflux-omeprazole.aspx acid reflux omeprazole | acid reflux omeprazole
http://dotnet.org.za/members/which-glucosamine-chondroitin-is-the-best.aspx which glucosamine chondroitin is the best | which glucosamine chondroitin is the best
http://dotnet.org.za/members/geoda-software.aspx geoda software | geoda software
http://dotnet.org.za/members/generic-neurontin-watson.aspx generic neurontin watson | generic neurontin watson
http://dotnet.org.za/members/how-to-make-omeprazole-suspension.aspx how to make omeprazole suspension | how to make omeprazole suspension
http://dotnet.org.za/members/fish-antibiotic-_2600_-erythromycin.aspx fish antibiotic & erythromycin | fish antibiotic & erythromycin
http://dotnet.org.za/members/wats-up-with-the-drug-avandia.aspx wats up with the drug avandia | wats up with the drug avandia
http://dotnet.org.za/members/avelox-price.aspx avelox price | avelox price
http://dotnet.org.za/members/methotrexate-dosage.aspx methotrexate dosage | methotrexate dosage
http://dotnet.org.za/members/namenda-discussions.aspx namenda discussions | namenda discussions
http://dotnet.org.za/members/januvia-_2600_-drop-in-blood-pressure.aspx januvia & drop in blood pressure | januvia & drop in blood pressure
http://dotnet.org.za/members/levaquin-toxicity-and-bowel-function.aspx levaquin toxicity and bowel function | levaquin toxicity and bowel function
http://dotnet.org.za/members/motrin-liquigel.aspx motrin liquigel | motrin liquigel
http://dotnet.org.za/members/aricept-maximum-dose.aspx aricept maximum dose | aricept maximum dose
http://dotnet.org.za/members/avelox-400mg.aspx avelox 400mg | avelox 400mg
http://dotnet.org.za/members/avandia-attorneys-lexington.aspx avandia attorneys lexington | avandia attorneys lexington
http://dotnet.org.za/members/can-i-given-neurontin-to-my-beagle.aspx can i given neurontin to my beagle | can i given neurontin to my beagle
http://dotnet.org.za/members/methotrexate-and-celebrex.aspx methotrexate and celebrex | methotrexate and celebrex
http://dotnet.org.za/members/toprol-xl-dosage-side-effects-fosamax.aspx toprol xl dosage side effects fosamax | toprol xl dosage side effects fosamax
http://dotnet.org.za/members/clindamycin-versus-erythromycin.aspx clindamycin versus erythromycin | clindamycin versus erythromycin
http://dotnet.org.za/members/apo-omeprazole-and-alcohol.aspx apo omeprazole and alcohol | apo omeprazole and alcohol
LikeLike
http://dotnet.org.za/members/motrin-and-bone-healing.aspx motrin and bone healing | motrin and bone healing
http://dotnet.org.za/members/prednisone-versus-medrol-for-poison-ivy.aspx prednisone versus medrol for poison ivy | prednisone versus medrol for poison ivy
http://dotnet.org.za/members/cortisone-and-lidocaine-ointment.aspx cortisone and lidocaine ointment | cortisone and lidocaine ointment
http://dotnet.org.za/members/how-does-erythromycin-work.aspx how does erythromycin work | how does erythromycin work
http://dotnet.org.za/members/geodon-80-mg.aspx geodon 80 mg | geodon 80 mg
http://dotnet.org.za/members/can-you-drink-alcohol-and-take-levaquin.aspx can you drink alcohol and take levaquin | can you drink alcohol and take levaquin
http://dotnet.org.za/members/motrin-before-oral-surgery.aspx motrin before oral surgery | motrin before oral surgery
http://dotnet.org.za/members/depo-medrol-generic.aspx depo medrol generic | depo medrol generic
http://dotnet.org.za/members/motrin-advil.aspx motrin advil | motrin advil
http://dotnet.org.za/members/folic-acid-with-methotrexate-in-psoriasis.aspx folic acid with methotrexate in psoriasis | folic acid with methotrexate in psoriasis
http://dotnet.org.za/members/is-neurontin-used-to-treat-neuropathy.aspx is neurontin used to treat neuropathy | is neurontin used to treat neuropathy
http://dotnet.org.za/members/avandia-lawyers-sc.aspx avandia lawyers sc | avandia lawyers sc
http://dotnet.org.za/members/depo-medrol-for-sneezing-cats.aspx depo medrol for sneezing cats | depo medrol for sneezing cats
http://dotnet.org.za/members/low-cost-naltrexone.aspx low cost naltrexone | low cost naltrexone
http://dotnet.org.za/members/erythromycin-dental-abscess.aspx erythromycin dental abscess | erythromycin dental abscess
http://dotnet.org.za/members/lumigan-eye-closes.aspx lumigan eye closes | lumigan eye closes
LikeLike