Form Builder: Create a custom control for file upload
Hi,
I need to add a fileupload to a form, but I am struggling with how to create a control for form builder. Everything seems working fine, but the value (filename) is not saved into the database after I submit a form. Can anyone point out what I did wrong? Thanks a lot.
Stephen
FileUploader.ascx
<%@ Control Language="C#" %>
<
asp:Label
runat
=
"server"
ID
=
"titleLabel"
CssClass
=
"sfTxtLbl"
Text
=
"title label"
></
asp:Label
>
<
asp:FileUpload
ID
=
"FileUpload1"
runat
=
"server"
/><
br
/>
<
asp:Label
runat
=
"server"
ID
=
"exampleLabel"
CssClass
=
"sfExample"
Text
=
"example Label"
></
asp:Label
><
br
/>
<
asp:Label
runat
=
"server"
ID
=
"descriptionLabel"
CssClass
=
"sfExample"
Text
=
"description Label"
></
asp:Label
>
// ----------------------------------------------------------------------------------------------------------
// <
copyright
file
=
"FileUploader.cs"
company
=
"Telerik"
>
// Authored by Falafel Software.
// </
copyright
>
// ----------------------------------------------------------------------------------------------------------
namespace CustomFormControls
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Telerik.Sitefinity.Data.Metadata;
using Telerik.Sitefinity.Metadata.Model;
using Telerik.Sitefinity.Model;
using Telerik.Sitefinity.Modules.Forms;
using Telerik.Sitefinity.Modules.Forms.Web.UI.Fields;
using Telerik.Sitefinity.Security;
using Telerik.Sitefinity.Web.UI;
using Telerik.Sitefinity.Web.UI.Fields;
using Telerik.Sitefinity.Web.UI.Fields.Config;
using Telerik.Sitefinity.Web.UI.Fields.Enums;
using Telerik.Web.UI;
/// <
summary
>
/// Class used to create custom control for Form Builder
/// </
summary
>
[DatabaseMapping(UserFriendlyDataType.ShortText)]
public class FileUploader : FieldControl, IFormFieldControl
#region Fields
/// <
summary
>
/// Private field for metaField
/// </
summary
>
private IMetaField metaField = null;
#endregion
#region Constructor
/// <
summary
>
/// Initializes a new instance of the FileUploader class.
/// </
summary
>
public FileUploader()
#endregion
#region Public properties (will show up in dialog)
/// <
summary
>
/// Example string
/// </
summary
>
public override string Example get; set;
/// <
summary
>
/// Title string
/// </
summary
>
public override string Title get; set;
/// <
summary
>
/// Description string
/// </
summary
>
public override string Description get; set;
#endregion
#region IFormFieldControl members
/// <
summary
>
/// Gets or sets MetaField property to persist data from control to the DB when form is submitted
/// </
summary
>
[TypeConverter(typeof(ExpandableObjectConverter))]
public IMetaField MetaField
get
if (this.metaField == null)
this.metaField = this.LoadDefaultMetaField();
// Add unique field name
this.metaField.FieldName = "FileUploader_" + this.ClientID;
return this.metaField;
set
this.metaField = value;
#endregion
#region Value method
/// <
summary
>
/// Get and set the value of the field.
/// </
summary
>
public override object Value
get
return this.FileUpload1.FileName;
set
//this.TextBox1.Text = value.ToString();
#endregion
#region Labels on control template
/// <
summary
>
/// Gets reference to the TitleLabel
/// </
summary
>
protected internal virtual Label TitleLabel
get
return this.Container.GetControl<
Label
>("titleLabel", true);
/// <
summary
>
/// Gets reference to the DescriptionLabel
/// </
summary
>
protected internal virtual Label DescriptionLabel
get
return Container.GetControl<
Label
>("descriptionLabel", true);
/// <
summary
>
/// Gets reference to the ExampleLabel
/// </
summary
>
protected internal virtual Label ExampleLabel
get
return this.Container.GetControl<
Label
>("exampleLabel", this.DisplayMode == FieldDisplayMode.Write);
#region Template
/// <
summary
>
/// Specify a template for the control
/// </
summary
>
protected override string LayoutTemplateName
get return "CustomFormControls.Resources.FileUploader.ascx";
#endregion
/// <
summary
>
/// Reference to the TitleControl
/// </
summary
>
protected override WebControl TitleControl
get
return this.TitleLabel;
/// <
summary
>
/// Reference to the DescriptionControl
/// </
summary
>
protected override WebControl DescriptionControl
get
return this.DescriptionLabel;
/// <
summary
>
/// Gets the reference to the control that represents the example of the field control.
/// Return null if no such control exists in the template.
/// </
summary
>
/// <
value
></
value
>
protected override WebControl ExampleControl
get
return this.ExampleLabel;
#endregion
#region Textbox on control
/// <
summary
>
/// Gets reference to the FileUpload1 control
/// </
summary
>
protected virtual FileUpload FileUpload1
get
return this.Container.GetControl<
FileUpload
>("FileUpload1", true);
#endregion
#region Script methods
/// <
summary
>
/// Get list of all scripts used by control
/// </
summary
>
/// <
returns
>List of all scripts used by control</
returns
>
public override IEnumerable<
ScriptDescriptor
> GetScriptDescriptors()
var descriptor = new ScriptControlDescriptor(this.GetType().FullName, this.ClientID);
descriptor.AddComponentProperty("fileUpload", this.FileUpload1.ClientID);
descriptor.AddProperty("displayMode", this.DisplayMode); // Pass the display mode value
// Pass the field name - this is VERY IMPORTANT - if this value isn't passed the backend publishing will not work
descriptor.AddProperty("dataFieldName", this.MetaField.FieldName);
return new[] descriptor ;
/// <
summary
>
/// Get reference to all scripts
/// </
summary
>
/// <
returns
>Reference to all scripts</
returns
>
public override IEnumerable<
System.Web.UI.ScriptReference
> GetScriptReferences()
var scripts = new List<
ScriptReference
>(base.GetScriptReferences())
new ScriptReference("CustomFormControls.Resources.CustomFormControls.js", this.GetType().Assembly.FullName),
new ScriptReference("Telerik.Sitefinity.Web.UI.Fields.Scripts.FieldDisplayMode.js", "Telerik.Sitefinity"),
;
return scripts;
#endregion
#region InitializeControls method
/// <
summary
>
/// You have to implement the custom logic you want to have inside IntializeControls()
/// </
summary
>
/// <
param
name
=
"container"
>Style cop won't shut up</
param
>
protected override void InitializeControls(GenericContainer container)
// Set the label values
this.ExampleLabel.Text = this.Example;
this.TitleLabel.Text = this.Title;
this.DescriptionLabel.Text = this.Description;
//this.FileUpload1.FileName = GetCurrentSitefinityUser();
#endregion
#region Get Current User
/// <
summary
>
/// Get the full name for the currently logged-in Sitefinity user.
/// </
summary
>
/// <
returns
>String with full name of current user, or empty string if user not logged in.</
returns
>
private static string GetCurrentSitefinityUser()
Telerik.Sitefinity.Security.Web.UI.ProfileView pv = new Telerik.Sitefinity.Security.Web.UI.ProfileView();
Guid currentUserGuid = pv.CurrentUser.UserId;
if (currentUserGuid != Guid.Empty)
var userManager = UserManager.GetManager("Default");
var user = userManager.GetUser(currentUserGuid);
return user.FirstName + " " + user.LastName;
else
return String.Empty;
#endregion
Type.registerNamespace("CustomFormControls");
CustomFormControls.FileUploader = function (element)
this._fileUpload = null;
CustomFormControls.FileUploader.initializeBase(this, [element]);
CustomFormControls.FileUploader.prototype =
/* --------------------------------- set up and tear down --------------------------------- */
/* --------------------------------- public methods ---------------------------------- */
// Gets the value of the field control.
get_value: function ()
return this._fileUpload.get_value();
,
// Sets the value of the text field control depending on DisplayMode.
set_value: function (value)
this._fileUpload.set_value(value);
,
/* --------------------------------- event handlers ---------------------------------- */
/* --------------------------------- private methods --------------------------------- */
/* --------------------------------- properties -------------------------------------- */
get_fileUpload: function ()
return this._fileUpload;
,
set_fileUpload: function (value)
this._fileUpload = value;
CustomFormControls.FileUploader.registerClass('CustomFormControls.FileUploader', Telerik.Sitefinity.Web.UI.Fields.FieldControl);
Hello Stephen,
Unfortunately upload controls for forms are not supported right now, because the upload somehow interferes with the Form's Lifecycle. This upload upon form submission is on our roadmap for the upcoming releases and soon you will be able to have this out-of-the-box. Sorry for the inconvenience caused.
Please let me know if I can help you with something else.
Thanks Svetoslav.
As we need the file upload feature for one of our site urgently, I tried to create a custom upload control according to the post, blog.falafel.com/.../Creating_Custom_Form_Controls_in_Sitefinity_4_0.aspx. The original custom control is working, but after I changed the textbox to file upload control, it stops working. Can you see the code snippets pasted above and give me some help? Thanks.
Stephen
Hi Stephen,
What I meant was that we have previously tried (with other clients, as well) to create such a custom control that uploads a file on form submission (also tried with an async upload) but with no success. When we spoke to the developers they answered that this cannot be done right now, because the way the forms get submitted, you cannot have a file upload at the same time. However, as I've said, we have taken this issue into account and it will be provided as an out of the box feature very soon.
Regards,Is it still the case that it is not possible to implement a custom form field that allows users to upload documents?
Thanks,
Antoine
Hello Antoine,
Unfortunately, the functionality of having to upload the file along with the submission of the form is not possible with the current implementation of the Form widget.
The submit button submits to the form widget and it processes all form controls, but only takes their values (field.Value) and doens`t upload the stream form the selected file stream.
However, for your convenience I am attaching an FileUpload control, which you can use in the meantime. You can also vote for the PITS item and track its status as well.
Hi Velev,
I've upvoted this feature and noticed it wasn't scheduled, although you did mention it was on the product roadmap, could you be so kind to share with us when this will be scheduled?
Thanks!
Hi
This feature is highly requested already for more than a year (high votes at PITS - they don't care)
When I was in London at Sitefinity conference they promised to us that it will be available already in Sitefinity 5.1
So if the say it will be implemented soon this means you will have to wait I guess for a year or so.
If I'm wrong good for us, because we need this feature urgently.
But I'm slowly loosing hope here because it never end up in road-map
Hi all,
Excuse us for any inconvenience that is caused by the lack of this functionality. I have consulted with our development teams, and they assured me that such feature will be implemented in one of the upcoming Sitefinity releases.
Kind regards,
Victor Velev
the Telerik team
Hi all,
Just wanted to follow up on this - can you tell us a bit more, on how do you image the control to be presented to the user? Do you expect it to allow more than one file to be uploaded? Also when a file is attached where do you expect to see all the attached files from the backend administration? Any additional feedback would be more than welcome!
Regards,
Victor Velev
the Telerik team
We had a recent use case where a client was having a contest and had applicants apply online. They used the form builder to build an application form. Since the form builder does not have a file upload field option, they requested that applicants email required documents separately.
I believe in this use case, there was only one file needed. I would not be surprised if use cases arise where more than one file would be desired.
Regarding where the files should be made available, it seems important for the user to be able to access the files from the form responses.
If there was a Media field that functions like the Media field for the custom modules, that would be excellent. I suppose that in the case of the forms, a library in which files are stored would need to be specified at the time the form field is setup rather than when the files are uploaded by users.
Hello Antoine,
Thank you for your feedback. I have forwarded it to our development teams. If you have more ideas or notes, please share them with us.
All the best,
Victor Velev
the Telerik team
Hi to all
We just posted the solution on Marketplace.
It is there for those who need this functionality before Sitefinity team will integrate it.