Welcome Guest Search | Active Topics | Sign In | Register

Uploader in Repeater Options
codeCutter
Posted: Monday, September 8, 2008 5:53:01 AM
Rank: Newbie
Groups: Member

Joined: 9/8/2008
Posts: 4
I have a requirement to track and manage a set of "core documents" that need to be supplied with an application. The list of these core documents are managed in a data set. A user is shown this list of core documents and can upload multiple of them at a time. The core list of documents therefore becomes a 'check list' that ensures that the user has submitted all the documents required for the application.

I have a few related questions regarding this. I have been able to display this core list of documents and been able to upload one or more of these. However, I can't seem to get a reference to the individual repeater item that contains the document type, status and other information regarding the individual core document. I've tried to hook the upload button to provide this link back to the individual repeater item but it doesn't seem to work. Any help would be appreciated.

Here's my code:

<asp:Repeater ID="coreDocuments" runat="server"
OnItemCommand="RepeaterOnItemCommand"
OnItemDataBound="RepeaterItemBound" >
<ItemTemplate>
<div id="fileUpload">
<p class="coreDocType"><%# DataBinder.Eval(Container.DataItem, "NewJobFileStatusDocumentName")%> </p>
<p class="coreDocInfo">
<asp:CheckBox ID="CheckBoxNotRequired" runat="server" ValidationGroup="coreDocValidation" /> Not Required
<asp:CheckBox ID="CheckBoxPending" runat="server" ValidationGroup="coreDocValidation" /> Pending
<asp:CheckBox ID="CheckBoxUploaded" runat="server" ValidationGroup="coreDocValidation" /> Uploaded
<cc1:MutuallyExclusiveCheckBoxExtender ID="CheckBoxExtender1" runat="server" TargetControlID="CheckBoxNotRequired" Key="coreDocValidation" />
<cc1:MutuallyExclusiveCheckBoxExtender ID="CheckBoxExtender2" runat="server" TargetControlID="CheckBoxPending" Key="coreDocValidation" />
<cc1:MutuallyExclusiveCheckBoxExtender ID="CheckBoxExtender3" runat="server" TargetControlID="CheckBoxUploaded" Key="coreDocValidation" />
</p>
<p class="coreDocInfo">
<asp:Label ID="Label5" runat="server" Text="ID: " /><%# DataBinder.Eval(Container.DataItem, "NewJobCoreFileStatusId")%><br />
<asp:Label ID="Label6" runat="server" Text="Status: " /><%# DataBinder.Eval(Container.DataItem, "NewJobCoreFileStatus")%><br />
<asp:Label ID="Label3" runat="server" Text="Last Updated: " /><%# DataBinder.Eval(Container.DataItem, "NewJobCoreStatusLastUpdated")%><br />
<asp:Label ID="Label4" runat="server" Text="Updated By: " /> <%# DataBinder.Eval(Container.DataItem, "NewJobCoreStatusLastUser")%>
</p>
</div>

<eo:AJAXUploader id="AJAXUploader1" runat="server" Width="450px"
AllowedExtension="pdf"
AutoPostBack="true"
CssClass="coreDocInfo"
OnFileUploaded="FileUploaded"
TempFileLocation="D:\Projects\Permits\uploads\temp" >
<LayoutTemplate>
<table cellspacing="0" cellpadding="2" width="720" border="0">
<tr>
<td width="99%">
<asp:PlaceHolder id="InputPlaceHolder" runat="server">Input Box Place Holder</asp:PlaceHolder>
</td>
<td>
<asp:Button id="UploadButton" runat="server" Text="Upload"
OnCommand="UploadOnCommand"
CommandName="Upload"
CommandArgument='<%# Eval("NewJobFileStatusDocumentName") %>' >
</asp:Button>
</td>
<td>
<eo:ProgressBar id="ProgressBar" runat="server"
ControlSkinID="None" Height="18px" Width="150px"
BorderColor="#336699" BorderStyle="Solid" BorderWidth="1px"
IndicatorColor="151, 198, 232">
</eo:ProgressBar>
</td>
</tr>
<tr>
<td colspan="3" class="loadedFiles">
<asp:PlaceHolder id="PostedFilesPlaceHolder" runat="server" >Posted Files Place Holder </asp:PlaceHolder>
<asp:Button id="DeleteButton" runat="server" Text="Delete Selected Files"></asp:Button>
</td>
</tr>
</table>
</LayoutTemplate>
</eo:AJAXUploader>
</ItemTemplate>
<SeparatorTemplate><hr /></SeparatorTemplate>
</asp:Repeater>


I have the following code behid - but it doesn't get executed:
public void RepeaterOnItemCommand(object sender, RepeaterCommandEventArgs e)
{
if (e.CommandName == "Upload")
{
// Determine the CoreDocumentID
int coreDocumentID = Convert.ToInt32(e.CommandArgument);
}
}
eo_support
Posted: Monday, September 8, 2008 7:20:12 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,193
Hi,

You can't really "reuse" the upload button in an uploader. The upload button in the uploader is strictly for user to start uploading file and it won't do anything else. So you will want to rely on something else to indentify the CoreDocumentID. One possible way we can think of is using our client side JavaScript API:

1. Place a hidden field in the form:

Code: HTML/ASPX
<input type="hidden" id="doc_id" name="doc_id" />


2. Remove "UploadButton" from the uploader's LayoutTemplate and replace it with a regular HTML button;

Code: HTML/ASPX
<input type="button" value="Upload" 
onclick='start_upload(this, <%# Eval("NewJobFileStatusDocumentName") %>);' />


I am not sure whether "NewJobFileStatusDocumentName" is an integer ID or string. It will be better for you to use an integer ID here. A string will cause quotation problems.

3. This way when you click the button, your start_upload method will be called with the doc ID. Function start_upload is implemented as follow:

Code: JavaScript
function start_upload(e, docId)
{
    //Save the doc ID first
    document.getElementById("doc_id").value = docId;

    //Now get the associated uploader control. Note here
    //we use eo_GetContainer to get the containing uploader
    //object because the button is inside the uploader
    var uploader = eo_GetContainer(e, "AJAXUploader");

    //Start upload
    uploader.upload();
}


4. You will then be able to add code in your server side Page_Load and check the value of the input variable doc_id. It will be something like this:

Code: C#
if  (IsPostBack)
{
    string docId = Request.Form["doc_id"];
    if (doc_id != null)
    {
        //A file is uploaded.....
        ......
    }
}


This should get your going. Hope this helps.

Thanks

codeCutter
Posted: Monday, September 8, 2008 10:00:49 PM
Rank: Newbie
Groups: Member

Joined: 9/8/2008
Posts: 4
Thanks for the quick reply - but unfortunately this does not work.

The HTML for the button's onclick event does not get evaluated correctly. It appears that when the button is inside the EO Uploader Layout Template the <%# Eval() %> is not interpreted correctly. I get a null / empty string when I use Eval() or a compliation error if I change this to DataBinder.Eval(Container.DataItem, "field"). The compliation error is "'EO.Web.AJAXUploader' does not contain a definition for DataItem".

If I move this HTML button to AFTER the EO Uploader control then the Eval is properly interpreted and the document reference is saved. However, the eo_GetContainer then fails and the var uploader is null.

Any other ideas?
eo_support
Posted: Tuesday, September 9, 2008 7:40:40 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,193
Hi,

In that case you can try something like this:

Code: HTML/ASPX
<ItemTemplate>
    <eo:AJAXUploader runat="server" id="AJAXUploader1" .....>
        .....
    </eo:AJAXUploader>
    <div runat="server" id="AJAXUploader1_AnchorDiv">
        <input type="button" value="Upload" 
            onclick='start_upload(this, <%# Eval("NewJobFileStatusDocumentName") %>);'>
    </div>
</ItemTemplate>


Point of interest:

1. The upload button is outside of the uploader, this ensures the data binding expression being correctly evaluated;
2. The parent element name "AJAXUploader1_AnchorDiv", starts with "AJAXUploader1". We will rely on this to get the uploader's client ID based on this parent element's client ID;

You start_upload function can then be as follow:

Code: JavaScript
function test(e, docId)
{
    //Get the parent element of the input element
    var id = e = e.parentNode.id;

    //Get the uploader's ID based on the parent element's
    //ID
    id = id.substr(0, id.length - 10);
    
    //Get the uploader object
    var uploader = eo_GetObject(id);

    //Perform other tasks....
    ......
}


The key is to get the correct client ID for the uploader so that we can call the uploader's upload method.

Hope this helps.

Thanks
codeCutter
Posted: Wednesday, September 10, 2008 5:53:52 AM
Rank: Newbie
Groups: Member

Joined: 9/8/2008
Posts: 4
Thanks - you help has been greately appreciated as I have been struggling with this for a couple of weeks trying differnt combinations!
These changes work functionality, although I had to combine your two javascript functions together.

The start_upload function now looks like:

function start_upload(e, docID)
{
// Save the doc ID first
document.getElementById("doc_id").value = docID;

//Get the parent element of the input element
var id = e = e.parentNode.id;

//Get the uploader's ID based on the parent element's ID
id = id.substr(0, id.length - 10);

//Get the uploader object
var uploader = eo_GetObject(id);

// Start upload
uploader.upload();
}

My file upload code behind now looks like this:
public void FileUploaded(object sender, System.EventArgs e)
{
EO.Web.AJAXUploader uploader = (EO.Web.AJAXUploader) sender;
foreach (EO.Web.AJAXPostedFile file in uploader.PostedFiles)
{
string tempFileName = file.TempFileName;

string applicationNbr = Convert.ToInt32(ApplicationID.Text).ToString("00000");
string newFileName = applicationNbr + "_" + file.ClientFileName;
string newFileName2 = newFileName.Substring(0, newFileName.Length-4) + "_" + DateTime.Now.ToString( "yyyy_MM_dd_hhmm" ) + ".pdf";

//Create the final file name based on the original file name
string finalFileName = Path.Combine(Server.MapPath("~/uploads"), newFileName);
string finalFileName2 = Path.Combine(Server.MapPath("~/uploads"), newFileName2);

//Move the file to the desired location
int docID = Convert.ToInt32(Session["CoreDocID"]);
if (tempFileName != null)
{
if (File.Exists(finalFileName)) {
File.Move(tempFileName, finalFileName2); // handle duplicate files with same filename
registerCoreFileUpload(docID, newFileName2); // Add document entry
}
else {
File.Move(tempFileName, finalFileName);
registerCoreFileUpload(docID, newFileName); // Add document entry
}
}
}
}


However, I have two final questions related to how this now looks.

1) The components of the upload are now spread over two lines. How do you position the new HTML upload button (the new one now in the DIV) so that it occurs alongside the standard EO upload now that the button is no longer within the Layout? Ideally I would like this to look similar to your standard layout with the button before the progress bar - but can live with the button after the progress bar.

2) As I am uploading each document I wanted to change the background color for the repeater item to indicate that the file has been uploaded (but only the uploaded file not the entire repeater). Any ideas on how this can be done. I've got a status field as part of the dataset which I can use during the repeater bind to set these background colours during the post back - but this kind of defeats the purpose of using the AjaxUploader in the first place.
eo_support
Posted: Wednesday, September 10, 2008 8:39:42 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,193
Hi,

As for your question:

1) There are a number of solutions. The easiest would be using a table. However if you wish to have a layout that is similar to the default layout, you may still need to consider placing the button inside the uploader. You can combine all the tricks previously discussed so that it can still trigger the right upload. One way be:
1. Render an additional tag element like "AJAXUploader1_AnchorDiv";
2. Data bind your data to that additional tag element. If you are not concern about XHTML validation, you can bind it the data directly to the element as a property; Otherwise you can render a small peice of JavaScript to set the data as a property of the element;
3. When the upload button is clicked (now inside the uploader), use eo_GetContainer to get the uploader first;
4. Based on the uploader's ID calcuate the ID of the tag element, then get the data you attached to it;

2) I am not sure whether I got your question correctly because I do not think using binding to set the background color during postback defeats the purpose of the uploader. The purpose of the uploader is to give you visual feedback and also allow users to perform other things while the file is being transferred. After the file is transferred, you can postback the page and that postback not only does not defeat the purpose of the uploader, but is also necessary for your server side code to "process" the file.

Hope this helps.

Thanks!

codeCutter
Posted: Wednesday, September 17, 2008 5:38:20 AM
Rank: Newbie
Groups: Member

Joined: 9/8/2008
Posts: 4
A followup on the continuation of this post:

1 - I ended up using a simple table to organise the controls. However, for the reasons mentioned earlier in this same thread the upload button could not be placed inside the Layout as it does not interpret the Eval properly (in particular DataItem was not supported within the Layout).

2 - For the updating of the information I could not seem to get server side access to the DIV containing the upload control and related information. However, I did mangage to get an asp:Panel to accomplish this. So, when an individual file is uploaded the background of the panel is changed, the document status is shown as "uploaded" and the actual filename is shown. This works fine as long as the EO:Uploader control has the AutoPostback=true.

The client had wanted to perform several browse and populate the filename for several files to be uploaded - with a single upload button at the end performing the upload. I can simulate this with the AutoPostback=false (akin to your Delayed Postback example). The current suggestions with a single hidden field to support a Document ID won't support this multiple files even though the PostedFiles property does provide the individual multiple files. What is missing is some mechanism to support additional data with the uploader - such as a Document ID, status (some documents can be marked as "not required"), previous filename (if uploaded earlier), etc that are related to specific posted file entries. If these additional 'user defined' properties were available with the upload control they could be set from database records and then interogated/set during the FileUpload event.
eo_support
Posted: Wednesday, September 17, 2008 6:21:31 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,193
Hi,

I am not sure if I understand your multiple file problem. But my understanding is that if you can attach a single DocumentID, you can attach anything. When the question is whether you can associate any data to the uploader, the difference would be "can" and "can not", not "one piece of information" or "two pieces of information". So I am a bit puzzled when you mentioned about multiple files.

Another option that may work for you is to story your data in the Page's ViewState. Since ViewState always got posted back, you can inspect view state data during FileUpload event. That way you can include multiple pieces of information based on different keys.

Hope this helps.

Thanks



You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.