+1-888-365-2779
Try Now
More in this section

Forums / Developing with Sitefinity / Forms - 2 Step Process

Forms - 2 Step Process

26 posts, 0 answered
  1. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    11 May 2015
    Link to this post
    Is it possible to create a form that when submitted goes to another web page with a larger form, but completes the details already submitted if that makes sense?  At sort of two stage form?
  2. Svetoslav Manchev
    Svetoslav Manchev avatar
    735 posts
    Registered:
    29 Nov 2016
    14 May 2015
    Link to this post
    Hi David,

    You can try implement such functionality using the Forms events.

    Subscribing for IFormEntryCreatedEvent you can redirect to a page you need and you have the information filled-in in for the form entry created.

    I hope this helps.

    Regards,
    Svetoslav Manchev
    Telerik
     
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Sitefinity CMS Ideas&Feedback Portal and vote to affect the priority of the items
     
  3. ch
    ch avatar
    25 posts
    Registered:
    14 May 2014
    15 May 2015
    Link to this post

    Another approach would be to register the RadTabStrip and RadMultiPage as form controls. Using this approach you would create one form that spans multiple tabs. This is something I have read about but never tried. However, you can find more information from the links below. 

    http://www.sitefinity.com/developer-network/forums/general-discussions-/forms-creation-customization-of-complex-forms​

    http://www.sitefinity.com/developer-network/forums/developing-with-sitefinity/radtabstrip-and-radmultipage

  4. gregory hernandez
    gregory hernandez avatar
    59 posts
    Registered:
    10 Jul 2009
    15 May 2015
    Link to this post

    I have not try this myself...but, plan to.

    It's by Tim Williamson. See here: https://github.com/timw255/timw255.Sitefinity and take a look at the video too.

  5. ch
    ch avatar
    25 posts
    Registered:
    14 May 2014
    15 May 2015
    Link to this post

    If you are unable to get the RadTabStrip and RadMultiPage to work in form designer you could also build a widget in Visual Studio that save​ data to the Sitefinity form.  I suspect this approach will be easier to implement. For an example see below:

    http://blog.falafel.com/forms-in-sitefinity/​

     

     

  6. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    15 Jul 2015
    Link to this post

    Hi Svetoslav,

     

    Still struggling with the best way to achieve this in Sitefinity. 

    I think in form1 I need a custom submit button that will redirect to the page with form2 on it and add the datafields from form1 in a querystring.

    for form2 I either need to subscribe to the IFormEntryCreatedEvent and populate the fields from the querystring, or create a custom form and use it's initialise function to populate the fields form the query string.

    Given the forms are already created what is the best (i.e. least amount of coding) required to get these forms to talk to one another.  And should I even be using Querystring for this?

  7. Steve
    Steve avatar
    3037 posts
    Registered:
    03 Dec 2008
    15 Jul 2015 in reply to David
    Link to this post

    @David

    Can you elaborate a bit?

    Do you need to STORE the data from Form 1, or are you just looking for like "Step 1" of a multipage form?

    Like you could use a Wizard to do a multi-step and save the results back to an SF Form

    Or if you want to do the querystring thing, you should be putting the FormId in the querystring and loading the resulting data onto Form 2, not literally passing the data fields themselves.

     Can you just give me more details?

  8. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    16 Jul 2015 in reply to Steve
    Link to this post

    Hi Steve,

     Yes I do want to store the data from Form 1, which is why I would like to use a Sitefinity form.  Basically it asks the house number and postcode of a property on the home page step 1, which then should redirect to Form 2 fill in the house number and postcode and then they have to fill in name, numbers, and other details.  I believe some people might give up at Form 2, so I want to keep the data in Form 1 for marketing and analysis.

  9. Steve
    Steve avatar
    3037 posts
    Registered:
    03 Dec 2008
    16 Jul 2015 in reply to David
    Link to this post

    Okay, if it was ME....I would make a single form to store all the data

    Basically the backend form designer is pointless, just a shell to store the data.  So put all the fields in there you want, maybe even prefix with like Form1 or Form2 on the developer names.

    So then you make a custom widget that would allow someone to fill in the few first fields, on submit save that data into the SF form, maybe have a custom field there to store a hash or token to access the form (so you're not exposing the ID).

    So then if the page loads with this token (a valid one) in the querystring, then load up page 2, and on save fill in the rest of the data to the form...make sense?

     Steve

  10. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    16 Jul 2015 in reply to Steve
    Link to this post

    So I would have Widget 1 on the home screen (that would write partial data to a form), then Widget 2 on the contact page that would load the data if a token was passed in the query string.

    That's certainly an option.  It might be me, but I end up feeling that Sitefinity just becomes a set of database routines.  It felt great creating the contact form in 2 minutes in the designer, but now because I want some quite ordinary behaviour in the web world, I'm pretty much writing ASP.net from scratch, with database helpers?  Perhaps I'm being too negative?

  11. Steve
    Steve avatar
    3037 posts
    Registered:
    03 Dec 2008
    16 Jul 2015 in reply to David
    Link to this post

    My way is just one way...only because I'd want to keep all the form data together.  You can certainly just MAKE 2 forms in the backend, and then override the default forms widget to extend it with any extra functionality you'd need (like checking a querystring to load stuff in).

    You're talking about something even more advanced than a 2 page form right, that's not something supported out of the box.  I can hack a 2 page form in with layouts and javascript, but this would take just a bit of code.

    You are being too negative, it's not that bad! :)

  12. ch
    ch avatar
    25 posts
    Registered:
    14 May 2014
    16 Jul 2015
    Link to this post

    I think the simplest approach (at least in my mind) is to use the asp.net MultiView control and build one widget ​containing both forms.  What makes this simpler is that you don't have to pass values from one page to the other.  In the codebehind you can access the form controls from both views, even while a view is inactive. When the ActiveViewChanged event is called you get the values you want from Form1 and assign them to the controls you want in Form2.  This also gives you the option to not save to the database until the save button on Form2 is clicked. The Form1 save button would merely change the active view. An event handler would than populate Form2 from Form1. 

    Your'e gripes are legitimate but apply to all content management systems. 

     

    https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.multiview.activeviewchanged(v=vs.100).aspx

     

    http://www.beansoftware.com/ASP.NET-Tutorials/MultiView-Control.aspx

  13. Steve
    Steve avatar
    3037 posts
    Registered:
    03 Dec 2008
    16 Jul 2015 in reply to ch
    Link to this post
    @ch Forms are on separate pages though
  14. ch
    ch avatar
    25 posts
    Registered:
    14 May 2014
    16 Jul 2015 in reply to Steve
    Link to this post

    @Steve, my bad Form1 is on the home page and Form2 is on the contact page.

  15. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    17 Jul 2015
    Link to this post

    I think I'm going to go down the event route, and see if I can add any field with a QS in it's name to a query string.

    One thing I also need is a hidden field to say which page should be redirected to and to add the querystring.

    The documentation seem to indicated there are ReadOnly and HiddenModes for form controls in the advanced section, but I can't find them.  Is this version specific, I'm using 7?

    http://docs.sitefinity.com/for-developers-make-a-field-in-a-form-response-hidden-or-read-only-on-the-frontend

     

  16. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    20 Jul 2015
    Link to this post

    OK so I've used the event (see below) to build a query string and redirect.  Now, how do I read these values in form2.  Is there an event which renders the form Svetoslav?

    public static void FormsEventHandler(IFormEntryCreatedEvent eventInfo)
    {
    var controls = eventInfo.Controls;
    string qs="";
    var redirect = eventInfo.Controls.Where(c => c.FieldName == "Redirect").FirstOrDefault();
    if (redirect!=null) {
    //get page to redirect to
    String url = redirect.Title;
    //build query string
    var qsControls = eventInfo.Controls.Where(c => c.FieldName !=null && c.FieldName.Left(2) == "QS");
    foreach(var control in qsControls)
    {
    qs += control.FieldName+"="+control.Value+"&";
    }

    //Do the redirect
    HttpContext.Current.Response.Redirect(url+"?"+qs, true);
    }
    }

  17. Steve
    Steve avatar
    3037 posts
    Registered:
    03 Dec 2008
    20 Jul 2015 in reply to David
    Link to this post

    @David

    Override the default form control\widget...then add your custom version to the toolbox to drop on the page. ​You now have full access to the form\widget.  It has internal events to use.

     IMO, the above is rife with problems...injection, and no encoding on the values...like I said above, if you pass just the ID, you can then safely re-load the data in the inherited control.

  18. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    22 Jul 2015
    Link to this post

    Thanks, Steve, I think if I was writing this again I would go down that route, now I've got my head around the whole process.  I've added some url encode/decode and a quick check for special chars, etc.  Albeit the opportunity for injection doesn't seem to great as I'm not calling anything from the database?  I've attach the pasted the files below in case it helps anyone, it would be nice to have this kind of 2 step form process built in.  Probably to seasoned asp.net devs this is no problem, but to me it felt like a lot of work to achieve relatively little.

     

    formsevents.cs

    using System;
    using System.Linq;
    using System.Web;
    using Telerik.Sitefinity.Abstractions;
    using Telerik.Sitefinity.Data;
    using Telerik.Sitefinity.Services;
    using Telerik.Sitefinity.Modules.Forms.Events;
    namespace SitefinityWebApp.Events
    {
    public class FormEvents
    {
    public static void Start()
    {
    Bootstrapper.Initialized += new EventHandler<ExecutedEventArgs>(Bootstrapper_Initialized);
    }
    public static void Bootstrapper_Initialized(object sender, ExecutedEventArgs args)
    {
    if (args.CommandName == "Bootstrapped")
    {
    EventHub.Subscribe<IFormEntryCreatedEvent>(evt => FormsEventHandler(evt));
    }
    }
    public static void FormsEventHandler(IFormEntryCreatedEvent eventInfo)
    {
    var controls = eventInfo.Controls;
    string qs="";
    var redirect = eventInfo.Controls.Where(c => c.FieldName == "Redirect").FirstOrDefault();
    if (redirect!=null) {
    //get page to redirect to
    String url = redirect.Title;
    //build query string
    var qsControls = eventInfo.Controls.Where(c => c.FieldName !=null && c.FieldName.Left(2) == "QS");
    foreach(var control in qsControls)
    {
    qs += control.FieldName+"="+HttpUtility.UrlEncode((string)control.Value)+"&";
    }

    //Do the redirect
    HttpContext.Current.Response.Redirect(url+"?"+qs, true);
    }
    }
    }
    }

     smartformscontrol.cs

    using System;
    using System.Linq;
    using System.Web;
    using Telerik.Sitefinity.Modules.Forms.Web.UI;
    using Telerik.Sitefinity.Web.UI.Fields;
    using System.Text.RegularExpressions;
    namespace SitefinityWebApp.Widgets.SmartFormsControl
    {
    public class SmartFormsControl : FormsControl
    {
    protected override void OnInit(EventArgs e)
    {
    base.OnInit(e);
    this.Page.PreRenderComplete += new EventHandler(this.Page_PreRenderComplete);
    }
    protected void Page_PreRenderComplete(object sender, EventArgs e)
    {
    this.PrepopulateForm();
    }
    protected void PrepopulateForm()
    {
    var request = HttpContext.Current.Request;
    foreach (String key in request.QueryString.AllKeys)
    {
    if (key != null && key.Left(2)=="QS")
    {
    // Check key contains only lower case or upper case letters or numbers,
    // the apostrophe, a dot, or white space. Also check it is
    // between 0 and 40 characters long
    if (!Regex.IsMatch(HttpUtility.UrlDecode(key), @"^[a-zA-Z0-9'.\s]{0,40}$") || !Regex.IsMatch(HttpUtility.UrlDecode(request.QueryString[key]), @"^[a-zA-Z0-9'.\s]{0,40}$")) break;
    FieldControl ctrl = (FieldControl)this.FieldControls.Where(c => c.MetaField.FieldName == key).FirstOrDefault();
    if (ctrl != null)
    {

    ctrl.Value = HttpUtility.UrlDecode(request.QueryString[key]);
    }
    }
    }
    }

    }
    }

  19. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    22 Jul 2015 in reply to David
    Link to this post
    Oh, and still haven't figured out how to hide a field in a form yet, anyone?
  20. ch
    ch avatar
    25 posts
    Registered:
    14 May 2014
    23 Jul 2015
    Link to this post

    Instead of overriding the Form Widget you might find it simpler to create a user control in Visual Studio. That is the approach I have used in the past. The following article and documentation explains how:

     http://blog.falafel.com/forms-in-sitefinity/

    http://docs.sitefinity.com/for-developers-create-form-responses

    I will now describe how I would modify the widget created in Falafels tutorial to give you the same functionality you are after. 

    In this example the Falafel form will be split in 2. The first form will collect and save just the user's name and email. The second form will collect and save the user's name, email and message. In addition the second form will pre-populate with the values collected in the first form.

    The first step is to create both forms in Sitefinity's Form Designer.  Don't forget form1 contains just 2 of the fields and form2 contains all of the fields.

    Form1.ascx

    <div class="demo-section">
        <h2>Contact Us</h2>
        <ul id="fieldlist">
            <li>
                <asp:Label ID="lblName" runat="server">Name</asp:Label><br />
                <asp:TextBox ID="txtName" runat="server" CssClass="k-textbox"></asp:TextBox>
            </li>
            <li>
                <asp:Label ID="lblEmail" runat="server">Email</asp:Label><br />
                <asp:TextBox ID="txtEmail" runat="server" CssClass="k-textbox"></asp:TextBox>
            </li>
            <li>
                <asp:Button ID="btnSubmit" runat="server" OnClick="btnSubmit_Click" CssClass="k-primary k-button" Text="Submit" />
            </li>
        </ul>
    </div>

    Form1.ascx.cs (notice I added a response.redirect to the contact page. You will likely have to change the url it redirects to.

    protected void btnSubmit_Click(object sender, EventArgs e)
    {
        var manager = FormsManager.GetManager();
        var form = manager.GetFormByName("sf_contactus");
      
        Dictionary<string, string> dict = new Dictionary<string, string>();
        dict.Add("FormTextBox_C001", txtName.Text.Trim());
        dict.Add("FormTextBox_C003", txtEmail.Text.Trim());
      
        FormEntry entry = manager.CreateFormEntry(form.EntriesTypeName);
        foreach (var item in dict)
        {
            entry.SetValue(item.Key, item.Value);
        }
      
        HttpContext context = HttpContext.Current; if (context != null)
        {
            entry.IpAddress = context.Request.UserHostAddress;
            entry.UserId = SecurityManager.GetCurrentUser().UserId;
        }
      
        if (AppSettings.CurrentSettings.Multilingual)
        {
            entry.Language = System.Globalization.CultureInfo.CurrentUICulture.Name;
        }
      
        form.FormEntriesSeed = form.FormEntriesSeed + 1L;
        entry.ReferralCode = form.FormEntriesSeed.ToString();
        entry.SubmittedOn = System.DateTime.UtcNow;
      
        manager.SaveChanges();
        Response.Redirect("/Contact/?name=" + txtName.Text.Trim() + "&email=" + txtEmail.Text.Trim());
     
    }

     

    Form2.ascx

    <div class="demo-section">
        <h2>Contact Us</h2>
        <ul id="fieldlist">
            <li>
                <asp:Label ID="lblName" runat="server">Name</asp:Label><br />
                <asp:TextBox ID="txtName" runat="server" CssClass="k-textbox"></asp:TextBox>
            </li>
            <li>
                <asp:Label ID="lblEmail" runat="server">Email</asp:Label><br />
                <asp:TextBox ID="txtEmail" runat="server" CssClass="k-textbox"></asp:TextBox>
            </li>
            <li>
                <asp:Label ID="lblMessage" runat="server">Message</asp:Label><br />
                <asp:TextBox ID="txtMessage" runat="server" TextMode="MultiLine" CssClass="k-textbox"></asp:TextBox>
            </li>
            <li>
                <asp:Button ID="btnSubmit" runat="server" OnClick="btnSubmit_Click" CssClass="k-primary k-button" Text="Submit" />
            </li>
        </ul>
    </div>

      Form2.ascx.cs (notice I added Page_Load event handler to the tutorials sample, this is where the code for pre-populating the form takes place)

    protected void Page_Load(object sender, EventArgs e)
    {
           
        if (!Page.IsPostBack)
        {
            txtName.Text = Request.QueryString["name"].ToString();
            txtEmail.Text = Request.QueryString["email"].ToString();
     
        }
    }
     
    protected void btnSubmit_Click(object sender, EventArgs e)
    {
        var manager = FormsManager.GetManager();
        var form = manager.GetFormByName("sf_contactus");
      
        Dictionary<string, string> dict = new Dictionary<string, string>();
        dict.Add("FormTextBox_C001", txtName.Text.Trim());
        dict.Add("FormTextBox_C003", txtEmail.Text.Trim());
        dict.Add("FormTextBox_C004", txtMessage.Text.Trim());
      
        FormEntry entry = manager.CreateFormEntry(form.EntriesTypeName);
        foreach (var item in dict)
        {
            entry.SetValue(item.Key, item.Value);
        }
      
        HttpContext context = HttpContext.Current; if (context != null)
        {
            entry.IpAddress = context.Request.UserHostAddress;
            entry.UserId = SecurityManager.GetCurrentUser().UserId;
        }
      
        if (AppSettings.CurrentSettings.Multilingual)
        {
            entry.Language = System.Globalization.CultureInfo.CurrentUICulture.Name;
        }
      
        form.FormEntriesSeed = form.FormEntriesSeed + 1L;
        entry.ReferralCode = form.FormEntriesSeed.ToString();
        entry.SubmittedOn = System.DateTime.UtcNow;
      
        manager.SaveChanges();
    }


    Additional Tips:
    Do not use Sitefinity Thunder to create the Widgets.  Just create a normal Usercontrol for the Widgets.

    In the second form after the data is saved use Response.Redirect to take the user to a thank you page.

    There is a bug in the tutorial that I corrected in code I posted. I corrected it by replacing

    dict.Add("FormTextBox_C003", txtEmail.Text.Trim());
    dict.Add("FormTextBox_C004", txtEmail.Text.Trim());

    with

    dict.Add("FormTextBox_C003", txtEmail.Text.Trim());
    dict.Add("FormTextBox_C004", txtMessage.Text.Trim());

  21. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    23 Jul 2015
    Link to this post

    Ch,

    It's certainly another route, but it is still quite a bit of effort code to achieve.

    Also, I tried to make it so that the code would work throughout the site and easily copied to another site, so the redirect url is obtained from a hidden form field, and it will process any field that starts with "QS".  That way if I want the same functionality again I don't have to write any more widgets/forms, etc.  I just drop a hidden field on "Redirect" and name the form field QSsomething, and I don't need to do anything on the backend, if that makes sense.

     

  22. ch
    ch avatar
    25 posts
    Registered:
    14 May 2014
    24 Jul 2015 in reply to David
    Link to this post

    For the redirect try using a property instead of a hidden field.  You can than set the property when you add the Widget to the page.

     Form1.ascx.cs with property for redirect url

    public string DestinationUrl
    {
       get;set;
    }
      
    protected void btnSubmit_Click(object sender, EventArgs e)
    {
        var manager = FormsManager.GetManager();
        var form = manager.GetFormByName("sf_contactus");
        
        Dictionary<string, string> dict = new Dictionary<string, string>();
        dict.Add("FormTextBox_C001", txtName.Text.Trim());
        dict.Add("FormTextBox_C003", txtEmail.Text.Trim());
        
        FormEntry entry = manager.CreateFormEntry(form.EntriesTypeName);
        foreach (var item in dict)
        {
            entry.SetValue(item.Key, item.Value);
        }
        
        HttpContext context = HttpContext.Current; if (context != null)
        {
            entry.IpAddress = context.Request.UserHostAddress;
            entry.UserId = SecurityManager.GetCurrentUser().UserId;
        }
        
        if (AppSettings.CurrentSettings.Multilingual)
        {
            entry.Language = System.Globalization.CultureInfo.CurrentUICulture.Name;
        }
        
        form.FormEntriesSeed = form.FormEntriesSeed + 1L;
        entry.ReferralCode = form.FormEntriesSeed.ToString();
        entry.SubmittedOn = System.DateTime.UtcNow;
        
        manager.SaveChanges();
        Response.Redirect(this.DestinationUrl + "/?name=" + txtName.Text.Trim() + "&email=" + txtEmail.Text.Trim());
       
    }

     
  23. gregory hernandez
    gregory hernandez avatar
    59 posts
    Registered:
    10 Jul 2009
    24 Jul 2015
    Link to this post

    Oh, and still haven't figured out how to hide a field in a form yet, anyone?

    You can probably create a custom user control with an asp:HiddenField.

     I did it where I add a value to it via javascript. But, it can certainly be repurposed so that a value can be added when you drop the field in the UI form designer or with via javascript on the page.

     The hidden field would display in your form responses on the back-end as well.

    And, as an asp:HiddenField, it won't show up on the front end.

     Is this what you mean by "hide a field in the form?"

     

  24. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    27 Jul 2015 in reply to gregory hernandez
    Link to this post

    Gregory,

    I was going to go down that road, but the documentation indicated this is a feature already in Sitefinity?  But I can't find it?

    http://docs.sitefinity.com/for-developers-make-a-field-in-a-form-response-hidden-or-read-only-on-the-frontend

     

  25. gregory hernandez
    gregory hernandez avatar
    59 posts
    Registered:
    10 Jul 2009
    27 Jul 2015 in reply to David
    Link to this post

    Interesting. I did not know such a feature existed. I will take a look at that.

     When I needed it, and couldn't find any documentation quickly, I went the "hard way" route with creating the control. Again, nothing fancy as it is limited in its current state. I needed something quickly and rushed through it.

     I'll take a look at that feature and see if I find anything and report back.

  26. David
    David avatar
    114 posts
    Registered:
    19 Jul 2012
    01 Aug 2015 in reply to gregory hernandez
    Link to this post

    Well if the feature does exist, it's certainly difficult to find (hidden almost!).  I think it is version specific, would be nice to have this confirmed by Sitefinity though.

    In the meantime I've just set the class of the field to hide in the form control, and then just added this to my CSS:

    .hide {
    visibility: hidden;
    }

26 posts, 0 answered