Try our conversational search powered by Generative AI!

Webforms Form Blocks to MVC Form Blocks

Vote:
 

Hello,

We are in the process of converting from Webforms to MVC, and this is the first MVC project I've worked on.  On our current site we have a few blocks that are forms, such as a contact us form.  On the current site when the form is submitted we check if IsPostBack and then save the data to xforms with the below example.

var xform = XForm.GetForms().FirstOrDefault(f => f.FormName == "Contact Us");
if (xform != null) {
var form = XForm.CreateInstance((Guid)xform.Id);
var formdata = form.CreateFormData();
formdata.SetValue("fName", Request.Form["fName"]);
// more data saved
}

After that we then send the emails using a third party service.  The code that we use to send the emails makes referenes to items in the model such as CurrentBlock.FromEmail, which is set up for each block when it is created.

Part of the block model

[Display(
      GroupName = SystemTabNames.Content,
      Order = 1)]
public virtual XhtmlString ThankYouContent { get; set; }

[Display(
      GroupName = SystemTabNames.Content,
      Order = 2)]
public virtual XhtmlString IntroContent { get; set; }

[Display(
      GroupName = SystemTabNames.Content,
      Order = 3)]
[CultureSpecific]
public virtual string FromEmail { get; set; }

I created a ContactUsViewModel that would take the different fields that are requested, created the form in Index.cshtml, and set up the Controller very basically in hopes of just trying to submit the form and have it go back to the the Index ActionResult, and instead of displaying the form to display the ThankYouContent, but my attempts just displayed the form again without any Layout.

Example of code

Index.cshtml

@model ContactUsViewModel
@Html.PropertyFor(x => x.IntroContent) @using (Html.BeginForm("Submit", null) {
@Html.LabelFor(m => m.fName) @Html.TextBoxFor(m => m.fName
}

ContactUsViewModel.cs

public class ContactUsViewModel {
  public virtual XhtmlString IntroContent { get; set; }
  public virtual XhtmlString ThankYouContent { get; set; }
  [Required]
  public string fName { get; set; }
}

ContactUsControler.cs

public class ContactUsController : BlockController
    {
        public override ActionResult Index(ContactUs currentBlock)
        {
            var viewModel = new ContactUsViewModel();
            if (currentBlock != null)
            {
                viewModel.IntroContent = currentBlock.IntroContent;
            }

            return PartialView(viewModel);
        }

        [HttpPost]
        public ActionResult Submit()
        {
            return RedirectToAction("Index");
        }
    }

Obviously that didn't work, so I went and tried to find some other way of doing it and found the below link.

https://world.episerver.com/blogs/team-oshyn/dates/2016/3/posting-forms-with-episerver-mvc/

This got me farther, but we don't want to have to expose the data in Hidden fields (some of the forms have data that we don't want to be viewable like paths to email templates), we don't want to have the query string added to the URL, and I still wasn't able to get the ThankYouContent to show on the Success.cshtml page as in the ActionResult Submit the ContactUs model came back as null.

All that being said, I'm sure I'm missing something that is making this harder on myself, but I wasn't able to find too much recent info on how this can be done beyond the linked post and other articles about making form pages not blocks.

Any help would be greatly appreciated and if I'm missing something in this post please let me know and I'll do my best to respond.

Thank you,

Kevin Larsen

#196343
Aug 27, 2018 18:14
Vote:
 

Sorry, please note that the below code is actually correct in my code, just was bad copy and paste on my part.

@Html.TextBoxFor(m => m.fName

is actually

@Html.TextBoxFor(m => m.fName)
#196344
Aug 27, 2018 18:27
Vote:
 

Any help?

#196475
Aug 31, 2018 16:16
Vote:
 

I would strongly suggest looking into Episerver Forms for this if you need to build forms, gives you all the functionality you are asking for out of the box. XForms is completely dead, so imho should be avoided at all cost.

Remember that when creating a form in a block, the block is effectively a child action in mvc terms and they can't post back like normal page actions, because how would you handle routing for this? so you need to make all sorts of workarounds to get this to work like you probably read about already. This is not a limitation of Episerver but more of mvc, what would you do with two blocks on the same page that both need to post back? you need hidden fields for this to get it to work. 

Also the example you linked to uses TempData which in turn uses session state, which imho you should never use, so many issues with session state in general.

#196531
Sep 03, 2018 14:52
Vote:
 

Hi Thomas,

This is kind of what I thought, but raises issues with how the site was previously done then to bring it over to MVC.  Our account register and even our checkout steps were all done using blocks.  Obviously this means Forms can't be used because of the logic that needs to be done for each of the blocks from my limited knowledge of Forms can't be done.  Also, with EPiServer Forms from what I saw, sending emails has to be done on the server through SMTP.  We use a third party mailing service's API to send all of our emails, which I did not see a way to do so using Forms, at least from my searching.

Any additional info or guidance would be greatly appreciated!

Thank you,

Kevin Larsen

#196611
Edited, Sep 05, 2018 16:08
Vote:
 

Hi Kevin

When it comes to sending emails via a third party you can work with data posted via Episerver Form using custom form actors. These allow you to hook into the post-submit pipeline and do whatever you wish with the submitted form data, including sending email via a 3rd party. 

The documentation for custom actors is here: https://world.episerver.com/documentation/developer-guides/forms/implementing-a-customized-actor/ and a nice blog talking about them here https://www.dcaric.com/blog/episerver-forms-3-custom-actors

You can see an example where I have implemented a custom actor (to update a profile in the Episerver Insight Profile store) here: https://github.com/davidknipe/InsightFormFieldMapper/blob/master/InsightFormFieldMapper/Actors/UpsertInsightProfileActor.cs#L32 

As Thomas has mentioned xforms is dead doesn't have a future roadmap so even if you don't migrate as part of this upgrade you should certainly plan to migrate off it at some point.

David

#196702
Sep 09, 2018 21:11
Vote:
 

Hi David,

Thanks for the articles and examples! 

I have one question before I start digging into this more.  I've seen articles about creating custom form elements in code, but I didn't see anything about creating an entire custom form in code.  Is this something that can be done with EPiServer Forms, or is it only possible to create the form elements to be used in the editor to create the form?

Thanks again for the help!

Kevin Larsen

#196743
Sep 10, 2018 18:47
Vote:
 

Hi Kevin

It’s certainly possible to create a custom form in code but this would simply be a standard HTML form built in MVC that processes submitted form data in the controller in the traditional way. 

If you wanted to use Episerver Forms you could just build them as usual and then lock permissions down to stop editors accidentally editing or deleting them. Episerver Forms are just content under the hood so you can import/export them between environments as needed. 

David 

#196744
Sep 10, 2018 18:55
Vote:
 

Hi David,

With a custom form could we still save data to a created EPiServer Form without actually using the created EPiServer Fom?  Currently with our custom forms we save the data from that form to a Xform form that is created in the CMS, but not actually used on the page.  I have a basic example of what we do with a custom from to xform in my original post.

Thank you,

Kevin Larsen

#196746
Sep 10, 2018 19:03
Vote:
 

Hi Kevin

You can certainly use Episerver Forms just to render a form on the site then control how the data is processed yourself if that is your question? To stop Episerver Forms from persisting your data then simply uncheck the "Store form submissions" checkbox as described here: http://webhelp.episerver.com/latest/addons/episerver-forms/creating-a-form.htm 

Then you create your custom actor as described further up this chain. 

You end up with a form that you can extend/edit (with the correct permissions) straight in the Episerver UI and a hook into the form via a custom actor that you can work with in code.

David

#196754
Sep 11, 2018 0:09
Vote:
 

Hi David,

I guess I asked it wrong, but if I made a form in code could I send data from that form when it is submitted to an EPiServer Form (set up with the same fields) and have the data that was submitted from the coded form stored in the EPiServer Form?  Currently the forms we have created in blocks send there data to a Xform version with the same fields so that data can be stored in the Xforms table in the database.

Thank you,

Kevin Larsen

#196779
Sep 11, 2018 15:08
Vote:
 

Hi Kevin

Episerver Forms can be treated (and are under the hood) blocks. So you may not need to create custom blocks at all and can just create an Episerver Form and drag it onto the page you want and use it to collect data.

Fogetting the original implementation, do you have a specific reason for wanting to create custom form markup? All the markup used in Episerver Forms can be edited so you may not need to do any/much custom work at all?

David

#196784
Sep 11, 2018 16:05
Vote:
 

Hi David,

Below are some of the reasons why I believe we would need custom form markup.  I'm not sure if they can be done with EPiServer Forms or not, but from what I've seen using it on an Alloy site I set up I don't think they are in the base version.

  • When a user is not logged in to our site we display a reCaptcha, if the user is logged in the reCaptcha is not displayed.
  • When a user is not logged in they have to fill out the entire form, if the user is logged in the fields are filled in with their user info.
  • We have custom validation set to follow business rules, along with using field masking on some fields to format the input from the user

Those are a few of the things that are currently in our custom form blocks that I don't know if is possible with the base version of EPiServer Forms.  I know that custom form elements can be created, so maybe some of those things can be implemented that way or even implemented into the base elements.

Some of the other things that are custom to the forms I believe could be handled with custom actors, having followed the guide about how to create them.

Thank you,

Kevin Larsen

#196792
Edited, Sep 11, 2018 17:33
Vote:
 

Hi Kevin

  • Episerver Forms contain form elements that are arranged just like blocks on a page, so can be personalised. This means you could have a "logged in" visitor group which is used to show/hide the reCaptcha element.
  • It should possibe to populate form elements based on their info though this would require some custom code
  • Yes custom validation is certainly possible, either using the built in regex validation or by extending with a custom element

My gut feel here says install a default Alloy site, add Episerver Forms to it and experiement. Challenge the client (if possible) to try and use as much out the box functionality as possible then add light touch customisation/enhancement where necessary. You could get a long way through your requirement to capture contact info using out the box features.

David

#196794
Sep 11, 2018 17:55
Vote:
 

Hi David,

Thanks for all your help with this!  I'll continue experimenting on the Alloy site and see if I run into any other issues along the way.

Thank you,

Kevin Larsen

#196795
Sep 11, 2018 18:05
Vote:
 

Kevin,

it is fairly easy to extract the views from the forms package and customize them as much as you need. The views are done in webform views unfortunately in the nuget package, but can easily be changed into razor views. It is also fairly easy to build custom form elements if business requirements change. Also if you want to control field names that you allow the editor to use when setting up a form, that  can also be done, it is very customizable.

Thomas

#196804
Sep 12, 2018 7:20
Vote:
 

Hi David,

I'm making good progress with the custom actor and custom elements, but I have a question about the actual submission of the data.  Going off of this guide that you shared earlier, that is working with data that has already been submitted and saved in the form.  We currently have a check on a certain field that if it has data in it that we don't want to do the normal behind the scenes behavior (save data and send emails), but still behave like it did (show the success message).

I found your response to a post for a similar issue, but I'm a bit lost as to how to use the solution for what I want to do.  Is there a way to incorproate the way the fields are able to be checked in the actor in the InitializationModule, even though they wouldn't have been submitted yet?  Is there a way of just deleting the submission data in the actor itself if that field has data in it?

Below is what I have in the CustomActor Run method up through the check of the ValidForm field and whether it should continue or not.

var model = Model as List<KeyValuePairModel>;
if (model == null || !model.Any())
{
  return string.Empty;
}

// skip execution if "runCustomActor is not set to "true"
var pair = model.FirstOrDefault(x => x.Key == "runCustomActor");
if (pair == null || pair.Value != "true")
{
  return string.Empty;
}
// Get data submitted
var submittedData = _formDataRepository.Service
                .TransformSubmissionDataWithFriendlyName(SubmissionData.Data, SubmissionFriendlyNameInfos, true)
                .ToList();
// Pair the submitted data with CustomDto fields
var customDto = submittedData.ToObject<CustomDto>();

if (!string.IsNullOrEmpty(customDto.ValidForm))
{
  return string.Empty;
}

Thank you,

Kevin Larsen

#196900
Edited, Sep 14, 2018 18:22
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.