Проверка на стороне клиента MVC2 для внедренного содержимого Ajax - PullRequest
5 голосов
/ 18 мая 2010

Я делаю Ajax-вызов и добавляю контент в форму внутри приложения MVC2. Мне нужно обновить метаданные проверки клиента для проверки моего нового содержимого.

 <script type="text/javascript"> 
//<![CDATA[
if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({"Fields":[{"
...
</script>

Есть ли способ генерировать эти метаданные для частичного просмотра?

Заранее спасибо.

Ответы [ 5 ]

6 голосов
/ 08 июня 2010

Я тоже несколько дней бился головой об стену и собирался пойти по пути удаления тега формы, но просто заставил его работать немного менее хакерским способом, если вы все еще заинтересованы. Мой сценарий был похож в том, что у меня есть форма с набором элементов для первоначальной проверки, но пользователи могут динамически добавлять новые строки через ajax.

Я сломаю это, так что, надеюсь, будет легче увидеть, что происходит. Глядя на исходный код MVC, форма и проверка работают примерно так:

Html.BeginForm () выводит открывающий тег формы, затем создает и возвращает новый экземпляр MvcForm, который внешне мало что делает, за исключением того, что вам легче управлять областью формы. Однако он создает новый FormContext и сохраняет его в ViewContext.FormContext. Именно этот FormContext отслеживает проверку клиента.

Последнее, что делает Html.BeginForm () - устанавливает свойство FormId нового FormContext, используя идентификатор тега формы. Это необходимо для того, чтобы клиентский сценарий мог сопоставлять формы и правила проверки.

Html.EndForm () удаляет MvcForm. Этот метод Dispose выводит закрывающий тег формы, а затем вызывает ViewContext.OutputClientValidation (), который является ответственным за вывод javascript. Наконец, он удаляет текущий FormContext и устанавливает его обратно в родительский FormContext или ноль, если его нет.

Таким образом, чтобы не выводить тег формы, нам нужно каким-то образом извлечь часть управления FormContext из конструктора / деструктора MvcForm.

Итак, в своем Частичном обзоре я сделал следующее:

Вверху я проверяю, имеет ли ViewContext.FormContext значение. Если это так, мы находимся в начальной загрузке, поэтому не нужно возиться. Если нет, то это ajax-вызов, поэтому я включаю проверку клиента, создаю новую MvcForm напрямую ( не с BeginForm) - это вызывает создание FormContext - и задаю для FormContext.FormId тот же Моя родительская страница

В конце представления я проверяю, есть ли у меня экземпляр формы, и если да, вызываю ViewContext.OutputClientValidation () и сбрасываю ViewContext.FormContext в ноль. Я не утилизирую () MvcForm, так как это выведет закрывающий тег, а MvcForm не содержит одноразовых объектов.

Каркас вида выглядит так:

<%
MvcForm dummyForm = null;
if (this.ViewContext.FormContext == null)
{
    Html.EnableClientValidation();
    dummyForm = new MvcForm(this.ViewContext);
    this.ViewContext.FormContext.FormId = "mainform";
}
%>

// standard partial view markup goes here

<%
if (dummyForm != null)
{
    this.ViewContext.OutputClientValidation();
    this.ViewContext.FormContext = null;
}
%>

Вы можете легко обернуть это в метод расширения

Phil

2 голосов
/ 31 мая 2010

Наконец получил его на работу.

Ответ прост: не тратьте время с MicrosoftMvcValidation.js. Он генерируется с помощью Script #, что затрудняет его расширение.

Переключиться на xVal и jQuery Validation . Ему не нужна форма для генерации метаданных проверки клиента. Кроме того, чтобы загрузить проверку для запроса AJAX, все, что вам нужно сделать, это вызвать следующее после получения нового HTML:

lForm.find("#placeholder").empty();                     
lForm.valid();
lForm.find("#placeholder").html(responseHtml);   

Это делает это. Сначала вы удалите старый контент. Затем повторите проверку, чтобы избавиться от потенциально устаревших ошибок проверки. Чем добавить новый контент. Работает как чам.

Также jQuery Validation позволяет действительно легко включать или отключать проверку для определенного поля (условная проверка).

1 голос
/ 01 июля 2010

У меня та же проблема, и я решаю ее с помощью файлов Future, а в MicrosoftMvcJQueryValidation.js я изменяю и файла, это:

$(document).ready(function () {
    var allFormOptions = window.mvcClientValidationMetadata;
    if (allFormOptions) {
        while (allFormOptions.length > 0) {
            var thisFormOptions = allFormOptions.pop();
            __MVC_EnableClientValidation(thisFormOptions);
        }
    }
});

для:

function chargeValidation() {
    var allFormOptions = window.mvcClientValidationMetadata;
    if (allFormOptions) {
        while (allFormOptions.length > 0) {
            var thisFormOptions = allFormOptions.pop();
            __MVC_EnableClientValidation(thisFormOptions);
        }
    }
}

и в содержимом после закрытия формы с использованием я называю 'chargeValidation ()', это решает проблему, с которой я сталкиваюсь, используя $ .get (action), содержащий проверку формы.

Я надеюсь помочь вам!

0 голосов
/ 21 мая 2010

Я добился определенного прогресса, но я не совсем доволен.

Задача № 1: Метаданные проверки клиента не генерируются, если в вашей частичной части нет Html.BeginForm ().Что в моем случае неверно, потому что я не обновляю всю форму, я обновляю ее части.

Решение для проблемы № 1: Добавить форму в частичном представлении, позволить MVC генерироватьклиент проверяет метаданные и удаляет теги формы с помощью фильтра действий.Давайте назовем это Hack # 1 .

public class RemoveFormFilterAttribute : ActionFilterAttribute
{       

    private static readonly MethodInfo SwitchWriterMethod = typeof(HttpResponse).GetMethod("SwitchWriter", BindingFlags.Instance | BindingFlags.NonPublic);

    private TextWriter _OriginalWriter;

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        _OriginalWriter = (TextWriter)SwitchWriterMethod.Invoke(HttpContext.Current.Response, new object[] {new HtmlTextWriter(new StringWriter())});
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        if (_OriginalWriter != null)
        {
            HtmlTextWriter lTextWriter =(HtmlTextWriter) SwitchWriterMethod.Invoke(HttpContext.Current.Response, new object[] {_OriginalWriter});

            string lOriginalHTML = lTextWriter.InnerWriter.ToString();

            string lNewHTML =  RemoveFormTags(lOriginalHTML);

            filterContext.HttpContext.Response.Write(lNewHTML);
        }
    }

Задача № 2: Первоначальные метаданные проверки клиента для страницы ушли к тому времени, когда у меня есть метаданные дляновый контент.

Решение для проблемы # 2: Сохраните исходные метаданные (печатную копию) и обновите их новыми файлами, затем вызовите методы, которые вы упомянули, чтобы позволить MVC узнать новые вещиприбыли.Давайте назовем это Hack # 2.

<script type="text/javascript">

    var pageMvcClientValidationMetadata;

    $(document).ready(function() {

        $("input[name='PaymentTypeName']").change(PaymentTypeChanged);

        //create a back-up of the ValidationMetadata
        pageMvcClientValidationMetadata = JSON.parse(JSON.stringify(window.mvcClientValidationMetadata));
    });

    function PaymentTypeChanged() {

        var selectedPaymentType = $("input[name='PaymentTypeName']:checked").val();

        $.ajax(
            {
                url: 'PersonalData/GetPaymentTypeHtml?&paymentType=' + selectedPaymentType,
                type: "GET",
                cache: false,
                success: GetPaymentTypeHtml_Success
            });
    }

    function GetPaymentTypeHtml_Success(result) {

        $('#divPaymentTypeDetails').html(result);

        UpdateValidationMetaData();
    }

    function UpdateValidationMetaData() {

        //update the ValidationMetadata
        for (i = 0; i < window.mvcClientValidationMetadata[0].Fields.length; i++) {
            pageMvcClientValidationMetadata[0].Fields.push(window.mvcClientValidationMetadata[0].Fields[i]);
        }

        //restore the ValidationMetadata
        window.mvcClientValidationMetadata = JSON.parse(JSON.stringify(pageMvcClientValidationMetadata));

        //Notify the Validation Framework that new Metadata exists
        Sys.Application.remove_load(arguments.callee);          
        Sys.Mvc.FormContext._Application_Load();            
    }

Сейчас.Будем благодарны за любые улучшения.

Hack # 1: Как я могу сгенерировать метаданные проверки клиента без фактической формы?

HAck # 2: Как добавить метаданные проверки страницы?

0 голосов
/ 19 мая 2010

Наконец-то нашел. После динамической загрузки контента вам необходимо зарегистрировать новую форму.

Поскольку я использую Facebox, я добавил его в код facebox, однако вы можете добавить его везде, где вам нужно, или в обратном вызове, если ваш модал или все, что вы загружаете, имеет событие afterLoaded.

Я обернул их в try / catch на тот случай, если я когда-нибудь использую facebox без проверки.

Просто запустите эти две строки ПОСЛЕ того, как ваш контент был загружен:

try {
        Sys.Application.remove_load(arguments.callee);
        Sys.Mvc.FormContext._Application_Load();
} catch (err) {/* MVC Clientside framework is likely not loaded*/ }
...