Sitecore:动态表单从Web窗体转换为MVC

时间:2016-05-25 19:56:35

标签: asp.net-mvc forms jquery-validate sitecore sitecore-mvc

我从sitecore 7.2升级到sitecore 8.1。我有5年的Web表单经验,但只有几个月的MVC接触。除了升级到8.1,我的老板想要从Web Forms更改为MVC。我的公司在Sitecore中使用Asp.Net Web Forms有一些复杂的表单逻辑,其中每个表单字段都是它自己的Sublayout(用户控件)。这允许内容编辑器根据业务提供的要求包括,不包括和重新排序表单字段。以下是我在Web窗体中完成此操作的方法(BTW我们也使用GlassMapper): 表单标记代码段:

<div id="formInputSection" runat="server">
    <div id="fields">
        <p class="required italic <%=reqFieldTextColor %>">
            <sc:Text ID="formReqFields" Field="Required Fields Text" runat="server" ClientIDMode="Static" DataSource="<%#lpOptions.Paths.FullPath %>" />
        </p>

        <asp:UpdatePanel ID="formUpdatePanel" runat="server">
            <ContentTemplate>
                <asp:Panel ID="formPanel" runat="server">
                    <asp:ValidationSummary ID="valSumFormSubmit" runat="server" DisplayMode="BulletList" ValidationGroup="formSubmit" CssClass="errorMsg" />
                    <div>
                        <sc:Placeholder ID="FormFieldsSect" Key="v2_ph_form_fields_col1" runat="server" />
                    </div>
                </asp:Panel>
            </ContentTemplate>
        </asp:UpdatePanel>
    </div>        

    <div id="form_action_submit" runat="server" class="form-action submit">
        <asp:LinkButton ID="btnSubmitForm1" CssClass="form-input submit white" OnClientClick="ValidateAndDisableButton();" OnClick="submit_Click" UseSubmitBehavior="false" runat="server" ClientIDMode="Static" Text="<%#Model.Form_Submit_Text %>" ValidationGroup="formSubmit" />
        <sc:Link ID="pgEditorFormSubmit1" Field="Editor Confirmation Link" CssClass="form-input submit white" runat="server" DataSource="<%#lpOptions.Paths.FullPath %>" Visible="false">
            <sc:Text Field="Form Submit Text" ID="pgEditorSubmitText1" runat="server" ClientIDMode="Static" DataSource="<%#lpOptions.Paths.FullPath %>" Visible="false" />
        </sc:Link>
    </div>
  

上面是FormSublayout的重要部分,它包含一个UpdatePanel,它包含各个表单字段子布局的占位符。如您所见,我还根据您添加到&#34; v2_ph_form_fields_col1&#34;中的字段进行动态验证。占位符。

接下来是其中一个基本字段子布局的标记。我将使用FirstName ...

    <%@ Control Language="C#" AutoEventWireup="true" CodeBehind="FirstNameField.ascx.cs" Inherits="MyNamespace.FirstName" %>
    <%@ Register TagPrefix="sc" Namespace="Sitecore.Web.UI.WebControls" Assembly="Sitecore.Kernel" %>
    <div class="clearfix form-input field text <%=LabelStyle %>">
        <asp:Label ID="Label1" AssociatedControlID="txtFirstName" Text="<%#Editable(x => x.First_Name) %>" runat="server" />
        <asp:TextBox ID="txtFirstName" runat="server" ClientIDMode="Static" type="text"></asp:TextBox>
        <asp:RequiredFieldValidator ID="validFirstName" runat="server" ControlToValidate="txtFirstName" ErrorMessage="<%#Model.First_Name_Required %>"
            Enabled="true" ValidationGroup="formSubmit" Display="None"></asp:RequiredFieldValidator>    
    </div>
    <br />
  

这个字段子布局就像我们所有的字段一样是独立的。它可以添加到我们的任何形式和功能而不会出错。 Code Behind将其输入写入会话,在提交时我们将会话中的所有值都映射到我们的联系对象,这将是我们在MVC中的模型......

public partial class FirstName : InheritsFromGlassUserControl<FormFields>
{
    protected override void Page_Load(object sender, EventArgs e)
    {
        if (this.Visible == true)
        {                
            SitecoreContext context = new SitecoreContext();
            Model = context.GetItem<FormFields>(Sitecore.Context.Database.GetItem(((Sublayout)Parent).DataSource).ID.Guid);
//ls is an object that we grab from session to update and put back into session
//to handle cross user control communication and such
            ls = GetSession();    
            LabelStyle = ls.MergeLabels ? "merge-label" : string.Empty;
            if (!string.IsNullOrWhiteSpace(txtFirstName.Text))
            {
                ls.CurrentLead.FirstName = txtFirstName.Text;
            }
            else
            {
                if (!IsPostBack)
                {
                    if (!string.IsNullOrWhiteSpace(ls.CurrentLead.FirstName) && !ls.IsReferralForm)
                        txtFirstName.Text = ls.CurrentLead.FirstName;
                }
            }       
//Put updated values in "ls" back into session for the next field to update, with its input        
            SessionDetails = ls;
            SetRenderingParameters();
        }
        this.DataBind();
    }
}
  

我遇到的问题是在MVC中实现这种解决方案的最佳方法是什么?我没有多少MVC的经验,而不仅仅是编写一个草率的解决方案我想知道是否有人有一个更好的实践示例,他们将如何(已)实现(ed)独立的表单字段给定MVC中的BeginForm()发布到一个模型,但是glassmapper&#34; model&#34;负责从sitecore填充的字段标签和字段验证错误消息内容。我还没有能够让两个模型共存于同一个cshtml文件中。我知道这很复杂,但即插即用表单字段的概念对于企业来说是一个非常有价值的解决方案。我找到了一个适用于Web窗体的版本;只是在MVC中无法绕过我的脑袋。

1 个答案:

答案 0 :(得分:0)

好的,所以上周我找到了这个问题的答案,我不想发布它,直到我有时间彻底解释。就像我在问题中所述,我们的表单只是sitecore占位符,我们在所有表单中重用相同的表单字段用户控件(子布局)。所以在MVC中我想要类似的东西。所以你在这个表单示例中看到,我们只有一个占位符,比如WebForms版本。 *注意以后对baseformhelper.js的引用。

@using Sitecore.Mvc
@using Sitecore.Mvc.Presentation

@inherits Glass.Mapper.Sc.Web.Mvc.GlassView<Contact_Form>
@{

}
@using (Html.BeginRouteForm(Sitecore.Mvc.Configuration.MvcSettings.SitecoreRouteName,
    FormMethod.Post))
{
    @Html.Sitecore().FormHandler("ContactForm", "SubmitContact")
    <div class="bottom-form-wrapper green-bg">
        <p class="form-title white">@Editable(x => x.Form_Headline_Text)</p>
        <p class="required white italic">@Editable(x => x.Required_Fields_Text)</p>
        <div id="divForm" class="twocol-bottom-form">
            @Html.Sitecore().Placeholder("v2_ph_formfields_col1")
        </div>
    <div class="clearfix"></div>
        <div id="form_action_submit" class="form-action submit">
            <input type="submit" id="lnkSubmitForm1" class="form-input submit red-bg white" value="@Editable(x => x.Submit_Button_Text)" />
        </div>
    </div><!--end form-wrapper-->    
<script type="text/javascript" src="~/scripts/Base-LP/BaseFormHelper.js" ></script >
}
...
  

在获得名字示例之前,我需要解释一下,我的模型是继承自Glass Mapper从项目模板创建的部分类,该模板负责为表单字段保存标签文本和验证消息。因此,不是每个用户控件都将它的值保存到会话中,而是每个局部视图都使用它自己的值更新模型状态。

//Contact model that inherits from glass mapper class
public class Contact : FormFields
{
    #region Properties

    [Required]
    public string FirstName { get; set; }

    [Required]
    public string LastName { get; set; }
...
  

由于我的模型的继承,我能够访问玻璃类的属性,我需要填充表格字段的标签和验证消息来自sitecore,同时仍然发布到我的表单的提交按钮时正确的联系人对象击中。

@using Sitecore.Mvc
@using Sitecore.Mvc.Presentation
@model Models.Contact
@{
//First_Name property comes from Contact class
//FirstName property comes form FormFields Glass Mapper Class
}

<div id="form_input_firstname" class="clearfix form-input text">
    @Html.LabelFor(x => x.FirstName, Model.First_Name)
    @Html.TextBoxFor(x => x.FirstName, new { id = "txtFirstName" })
    @Html.ValidationMessageFor(x => x.FirstName, null, new { id = "validFirstName" })
</div>
<script type="text/javascript" async>
//FirstName Validation Message
function FirstNameValidationMsg() {
    var myMsgNode = document.getElementById('validFirstName');
    //Find span that contains validation message
    if (myMsgNode.childElementCount > 0)
        myMsgNode.children[0].innerHTML = '@Model.First_Name_Required';//Overwrite validation with dynamic message from sitecore
}
</script>
  

现在,在Web窗体中,我使用了“asp:RequiredFieldValdidatior”,而在MVC中,我使用了jquery.validate和FoolProof Validation for MVC的组合。使用名字字段我不需要FoolProof验证,但我确实在jquery.validate.unobtrusive.js文件中的onError函数中添加了一行,以便sitecore对验证消息的内容有最终决定权。

function onError(error, inputElement) {  // 'this' is the form element
    var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
        replaceAttrValue = container.attr("data-valmsg-replace"),
        replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;

    container.removeClass("field-validation-valid").addClass("field-validation-error");
    error.data("unobtrusiveContainer", container);

    if (replace) {
        container.empty();
        error.removeClass("input-validation-error").appendTo(container);
    }
    else {
        error.hide();
    }
    //Call custom function to overwrite validation messages
    if (typeof setValidationMessages == 'function')
        setValidationMessages(inputElement[0]);
}
  

“setValidationMesages”函数位于baseformhelper.js中。如果它不可用,它将不会破坏jquery.validate,但如果是,它将调用添加到演示文稿的每个表单字段的验证。使用相同的“如果功能可用,请将其称为”逻辑。

//Base Form Helper
//Perform important form related functions and calculations here...

//Attempt to call function responsible for updating validation message with value from sitecore for each form field 
//if not available, nothing will break
function setValidationMessages(element) {
switch (element.id)
{
    case "txtFirstName":
        if (typeof FirstNameValidationMsg == 'function') {
            FirstNameValidationMsg();
        }
        break;
    case "txtLastName":
        if (typeof LastNameValidationMsg == 'function') {
            LastNameValidationMsg();
        }
        break;
...
  

因此,在sitecore中,我可以将动态字段添加到我的占位符中,他们将使用其值更新联系人模型,同时显示其唯一的验证消息。当我发布到我的控制器时,我决定添加到演示文稿的字段的所有值都存在,我可以用它们做我想要的。是的,问题解决了。直到下一次......

public class ContactFormController : Controller
    {
        [HttpPost]
        public ActionResult SubmitContact(Models.Contact postedContact)
        {            
            if(ModelState.IsValid)
            {
                //Do something like call to an API to post to Eloqua, CRM, or update Sitecore Contact for DMS/Experience Reports
            }
            else
            {
                //Do something else like log information about the contact so you know who tried to fill out your form even though your form submission logic is screwed up.
            }
        }
...