Building a Dynamic Form Builder - oh my!

I'm considering using the following solution to solve a problem of allowing users to "design' forms thru the web ui...

To create a web control, lets call it a "generic form builder"... where it renders forms based on a DB query..

The result set may look like

ControlType                              Label    DataSource
System.Web.UI.TextBox         -  Name      null
System.Web.UI.CheckBox       - Over 21    null
System.Web.UI.DropDownList - State      tblStates

etc..

I'll use this web control to accept input and it allows the flexibility of letting the end users design the fields they need to capture..

So if tommorrow they decide they want to capture "Favorite Food", they have the ability to add this..there are several issues, but the one i am getting a little hung up with the the dropdownlist...

my question is, have any of the uber coders out there created as similar "form builder" that can offer any suggestions on issues with viewstate, databinding or any other hurdles you may have jumped along the way..

thanks
LVL 9
Rodney HelsensAsked:
Who is Participating?
 
raterusConnect With a Mentor Commented:
Well here is where it gets difficult :-)

Depending on your level of coding ability, your best bet would probably be to create an object that represents any custom form your program could create.  Your aspx page instantiates this object, fills it with any values the form elements would need, and you load the UserControl with this object, which the usercontrol takes off and creates the form for you.  To get the values back out, you define your own methods in this object to do that.  What it is going to come down to is how elaborate you need to make this object be, like are you ever going to have to set a value in this dynamic form, how many different form elements could you possibly have, etc.

Or from your aspx page you can do this..ucd1.FindControl("SomeControl"), cast it, and grab the value.  

The solution to this can be very elegant and encapsulated, or it can be brute force.  You pick..

--Michael
0
 
raterusCommented:
I've done this before in one of my programs,  It is a Document Management program, where the user would design a "Template" of all the details they want to store about a particular type of document.  The user designs a form, and my asp.net page renders this page based on that (which is stored in a DB).

As far as databinding, how my program works, I programmed two options.  The first was to have one table for dropdownlist "listitem" values, where I put the text and the value, and an identifier to specify which created dropdownlist these were to be linked to.  This table was good for values that weren't necessarily stored elsewhere in our data.  When the program runs it is easy enough to get the data with this set up.  The other option I built in was to put a SQL Statement, and a connection string which my program would use to establish a connection to another datasource.  This sql string returned a result with datatextfield/datavaluefields already set, so my program could be generic enough to use any datasource, as long as the sql strings were built properly.

Getting the results of what they select is the fun part, you have to recreate the form on postback, since dynamically created controls aren't persisted across a postback.  That is the tricky part.

Let me know if you have any other questions,
--Michael
0
 
Rodney HelsensAuthor Commented:
Michael,
Thanks for the response, I do have another question regarding getting the values on postback.

I did a simple test aspx page and was able to create all the form elements and retrieve their values, but when I've tried to same tests using a web control, within a aspx page, I am losing the values selected.

I know this has to do with the timing of when the form elements are rebuilt, in my example, I am calling a method of the web control from my aspx on_load to build the form with a parameter telling it which form to build..

I have read about getting the form elements built in page_init or view state will not work..

Do you think it's possible to use the design of calling a method of the ascx to tell it to build the form, ie webControl.BuildForm(formID); from page_load on the aspx page?

Then on postback, I will call this webControl.BuildForm(formID) again, but it loses the values that were entered.

thanks again.
0
Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

 
raterusCommented:
By WebControl within an aspx page, I'm assuming you are meaning a UserControl (since you mentioned ascx).  Let me get this right, you have a usercontrol that will render the custom form automatically, based on a property you have selected, and on postback, you want anything you have typed/selected to be available from the usercontrol.  Are you wondering what you should call on the aspx page to recreate the UserControl correctly, and where to call it?

Just one question too if all this is correct,
Is the usercontrol dynamically added to your aspx page, or have you placed this within the aspx source?

--Michael
0
 
raterusCommented:
Here I'm just going to throw some code at you if my last post was on track.  Basically you don't need to worry about telling the usercontrol to Build itself, just expose a property, and when you change that, it knows it needs to remake itself.  Here was my sample, works great for me (hope you are using Visual Studio)

This is a webpage that has a usercontrol which either renders as a SingleLine textbox or a Multiline textbox based on a property "RenderAs".  The secret in all of this is the Public property of the Usercontrol, RenderAs, when you change it, you just tell it to Build the controls again.  No need for your aspx page to tell it to rebuild, it should already know how to do this.

WebForm1.aspx
<%@ Register TagPrefix="uc" TagName="Dynamic" src="WebUserControl1.ascx" %>
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="WebForm1.aspx.vb" Inherits="Test.WebForm1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
  <head>
    <title>WebForm1</title>
</head>
  <body>

    <form id="Form1" method="post" runat="server">
            <uc:Dynamic id="ucD1" runat="server" />
            <asp:button id="btnClick" runat="server" text="Postback" />
            <asp:button id="btnSwitch" runat="server" text="Switch RenderAs" />
    </form>

  </body>
</html>

WebForm1.aspx.vb
Public Class WebForm1
    Inherits System.Web.UI.Page

    Protected WithEvents btnClick As System.Web.UI.WebControls.Button
    Protected WithEvents btnSwitch As System.Web.UI.WebControls.Button
    Protected WithEvents ucD1 As WebUserControl1

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Put user code to initialize the page here
        If Not Page.IsPostBack Then
            ucD1.RenderAs = 1
        End If
    End Sub

    Private Sub btnClick_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnClick.Click
        'some stuff on postback
    End Sub

    Private Sub btnSwitch_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSwitch.Click
        If ucD1.RenderAs = 1 Then
            ucD1.RenderAs = 2
        Else
            ucD1.RenderAs = 1
        End If
    End Sub
End Class

WebUserControl1.ascx
<%@ Control Language="vb" AutoEventWireup="false" Codebehind="WebUserControl1.ascx.vb" Inherits="Test.WebUserControl1" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>

WebUserControl1.ascx.vb
Public Class WebUserControl1
    Inherits System.Web.UI.UserControl

    Public Property RenderAs() As Integer
        Get
            Return CInt(ViewState("renderas"))
        End Get
        Set(ByVal Value As Integer)
            ViewState("renderas") = Value
            MakeForm()
        End Set
    End Property

    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        'Put user code to initialize the page here
        MakeForm()
    End Sub

    Private Sub MakeForm()
        Me.Controls.Clear()

        If RenderAs = 1 Then
            Dim txtTest As TextBox = New TextBox
            Me.Controls.Add(txtTest)
        Else
            Dim txtTest As TextBox = New TextBox
            txtTest.TextMode = TextBoxMode.MultiLine
            Me.Controls.Add(txtTest)
        End If
    End Sub
End Class

0
 
Rodney HelsensAuthor Commented:
raterus, thanks again for the help.

I will read thru your code more thoroughly in a moment..to try and understand the implementation better, but one thing that jumps out at me is the postback code..

you never explicity re-render the user control, to create the form... so where/how do you access the values for those dynamically created form elements?  you show the line... 'some stuff on postback, but this is where I am experiencing the most trouble...  
how does the user control know on postback how to render itself in your example? how do you access the values of those objects?
thanks

0
 
raterusCommented:
Oh, in the page_load of the usercontrol is MakeForm(), that will remake the form on every page load.
0
 
Rodney HelsensAuthor Commented:
your feedback is appreciated, I think I am going to take another approach at this point, thanks
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.