logo

Flex: Open Attachments From The View

As part of the Contact Manager app I showed how you can display a paper clip icon in the column of a datagrid to represent documents with attachments.

Let's take this one step further and allow the user to download any one of the attachments straight from the view, without having to open the document.

If you re-open the demo app you should see a new option in the columns-to-show dropdown called Attachments:

 image

If you enable this column you'll see a dropdown box in the last column of any row that contains attachments. Clicking on a file name will launch/save it (depends on your browser preferences).

image 

Not an essential feature in every app but a nice example of something simple to achieve that adds value in certain circumstances.

How Did I Do It?

First thing I did was change the XML that defines both the columns and the data for the grid/view. Here it is:

 image

Notice theirs a column of type "download" which has a value of "files" and an attribute called "separator". This tell it to look for the "files" node of each document node and explode it using the value passed as a separator.

In the XML above it would give us an array of two file name strings - one for a PDF and one for a Word doc. It should be fairly obvious how this XML is produced in a Notes view, no?

In Flex, from within my View component, when looping the <columns> XML to build each column for the grid I added the following code:

if (column.hasOwnProperty("@type") && column.@type=="download"){
 var dlRenderer:ClassFactory = new ClassFactory(net.codestore.flex.DownloadColumnRenderer);

 dlRenderer.properties = {
  columnName: column.valueOf(),
  itemSeparator: column.@separator||"; ",
  view: this
 };

 col.headerRenderer = new ClassFactory(net.codestore.flex.DownloadHeaderRenderer);
 col.itemRenderer = dlRenderer;
 col.resizable = false;
 col.width=55;
}

The code for the DownloadColumnRenderer class looks like this:

<?xml version="1.0" encoding="utf-8"?>
<mx:Box xmlns:mx="http://www.adobe.com/2006/mxml" horizontalAlign="center" verticalAlign="middle">
        
        <mx:Script>
                <![CDATA[
                        import net.codestore.flex.View;
                        
                        [Bindable]
                        private var _columnName:String;
                        
                        [Bindable]
                        private var _separator:String;
                        
                        [Bindable]
                        private var _view:View;
                        
                        public function set columnName(colName:String):void{
                                _columnName = colName;
                        }
                        
                        public function set view(view:View):void{
                                _view = view;
                        }
                        
                        public function set itemSeparator(separator:String):void{
                                _separator = separator;
                        }
                        
                        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
                super.updateDisplayList(unscaledWidth, unscaledHeight);
             
                if (data && data.hasOwnProperty(_columnName) && data[_columnName].toString().length>0){
                        button.visible = true;
                        button.dataProvider = data[_columnName].split(_separator);
                } else {
                        button.visible=false;
                }
                        }
                        
                ]]>
        </mx:Script>
        
        <mx:PopUpMenuButton id="button" icon="{IconLibrary.PAPER_CLIP_ICON}"
                click="_view.openDocumentAttachment(data.@id, button.dataProvider[0])"
                itemClick="_view.openDocumentAttachment(data.@id, event.label)"
                height="20" width="45" cornerRadius="2"/>
</mx:Box>

Notice that we've passed to the DownloadColumnRenderer the instance of the View component in which it lives. It's this instance of the View that we call the openDocumentAttachment() method on. This method looks like this and lives inside View.mxml:

public function openDocumentAttachment(docId:String, fileName:String, save:Boolean=false):void{
 var _fileRef:FileReference = new FileReference();

 var urlReq:URLRequest = new URLRequest();
 urlReq.url = parentApplication.basePath + "0/"+docId + "/$file/"+fileName;

 if (save){
  _fileRef.download(urlReq); 
 } else {
  navigateToURL(urlReq, "_blank");
 }
}

All quite straight-forward and a quick example of how useful custom renderers can be in AdvancedDataGrids.

YMMV.

Comments

  1. Very nice Jake.

    Did you consider using the XML to structure the files? I mean use <files><file>file1.doc</file><file>word.doc</file><files>

    Not a big fan of using a separator as you never know when it might sneak in.

      • avatar
      • Jake Howlett
      • Wed 17 Feb 2010 02:36 PM

      Now you mention it, although I know how I came to avoid child nodes in grid-feeding XML, I'm not sure why I didn't use the format you suggested in this case.

      The trouble with datagrids in Flex is that a column can't deal with child nodes. Each <document> can only have nodes one level deep if they're to be shown by the grid.

      I have a draft blog for some time soon about a workaround I came up with related to the above, but, yeah, you're right - it might well be better to use your structure. Like you say the separator isn't foolproof.

      Jake

    • avatar
    • Bruno Zottelo
    • Thu 25 Feb 2010 10:49 AM

    Great code, like the others... had you think on implement a check box on view to multiple selection (I did) and a multi group collumn ?

    Have any idea how to save the configuration of columns show or others to don't lose them when run "refresh" ?

    Congratulations by your family and best regards.

      • avatar
      • Jake Howlett
      • Mon 1 Mar 2010 03:47 PM

      Hi Bruno,

      I did do a checkbox selection some time back:

      http://www.codestore.net/store.nsf/unid/BLOG-20091028-0634/

      Mutli-group columns should be easy to do. Just add another GroupingField to the array in the ActionScript.

      Funnily enough I have a draft blog in progress which describes how to remember the column order and visibility.

      Jake

Your Comments

Name:
E-mail:
(optional)
Website:
(optional)
Comment:


About This Page

Written by Jake Howlett on Wed 17 Feb 2010

Share This Page

# ( ) '

Comments

The most recent comments added:

Skip to the comments or add your own.

You can subscribe to an individual RSS feed of comments on this entry.

Let's Get Social


About This Website

CodeStore is all about web development. Concentrating on Lotus Domino, ASP.NET, Flex, SharePoint and all things internet.

Your host is Jake Howlett who runs his own web development company called Rockall Design and is always on the lookout for new and interesting work to do.

You can find me on Twitter and on Linked In.

Read more about this site »

Elsewhere

Here are the external links posted on the same day.

More links are available in the archive »

More Content