CActiveForm

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

Пришлось править файлы самого фреймворка.

Форма комментария рендерится на странице поста

в форме есть такой код




<?php $form=$this->beginWidget('CActiveForm', array(

	'id'=>'comment-form',

	'enableAjaxValidation'=>true,

    'method'=>'post',

    'action'=>$this->createAbsoluteUrl('/comment/create'),

    'clientOptions'=>array(

        'validateOnSubmit'=>true,

        'onSubmit'=>'js:function(data){$(\'#comment-button\').before(data.content);}'

    )

)); ?>



изменения которые произвел в jquery.yiiactiveform.js (отмечено //!!!)

(хм видно встроенная подсветка как то испортила некоторіе названия переменных и пр.)




....

			$.each(settings.attributes, function(i,attribute){

				settings.attributes[i] = $.extend({

					validationDelay : settings.validationDelay,

					validateOnChange : settings.validateOnChange,

					validateOnType : settings.validateOnType,

                                        onSubmit : settings.onSubmit, //!!!

					hideErrorMessage : settings.hideErrorMessage,

....

					});

					ajaxValidate(function(data) {

						$.each(settings.attributes, function(){

							if (this.status == 3) {

								updateInput(this, data.errors); //!!!

							}

						});

					});

....

			if (settings.validateOnSubmit) {

				var validated = false;

				$form.submit(function(){

					if (validated)

						return true;

					ajaxValidate(function(data){

						var hasError = false;

						$.each(settings.attributes, function(i, attribute){

							hasError = updateInput(attribute, data.errors) || hasError; //!!!

						});

						updateSummary(data.errors); //!!!

						if(!hasError) {

							validated = true;

                            if(settings.onSubmit){

                                settings.onSubmit(data);

                            }

                            else{

                                $form.submit();

                            }

							validated = false;

						}

					});

					return false;

				});

			}

....

	$.fn.yiiactiveform.defaults = {

		ajaxVar: 'ajax',

		validationUrl: undefined,

		validationDelay: 100,

		validateOnSubmit : false,

		validateOnChange : true,

		validateOnType : false,

                onSubmit : false, //!!!

		hideErrorMessage : false,

....



изменения в CActiveForm




....

	public static function validate($models, $loadInput=true, &$isValidated = null, &$rawResult = null)

	{

		$result=array();

		if(!is_array($models))

			$models=array($models);

		foreach($models as $model)

		{

			if($loadInput && isset($_POST[get_class($model)]))

				$model->attributes=$_POST[get_class($model)];

			$model->validate();

			foreach($model->getErrors() as $attribute=>$errors)

				$result[CHtml::activeId($model,$attribute)]=$errors;

		}


        if($isValidated !== null)

        {

            $isValidated = empty($result);

        }


        $result = array('errors'=>$result);


        if($rawResult !== null)

        {

            $rawResult = $result;

        }

		return function_exists('json_encode') ? json_encode($result) : CJSON::encode($result);

	}

....



в контроллере




....

    public function filters() {

        return array(

            'accessControl', // perform access control for CRUD operations

            'ajaxOnly + create',

        );

    }

....


    public function actionCreate() {

        $model=new Comment;


        $isValidated = false;

        $result = array();

        $json = CActiveForm::validate($model, true, $isValidated, $result);


        if($isValidated) {

            if(isset($_POST['Comment'])) {

                $model->attributes=$_POST['Comment'];

                if($model->save()){

                    $result['content'] = $this->renderPartial('_view',array('data'=>$model), true);

                    $result['success'] = true;

                    echo function_exists('json_encode') ? json_encode($result) : CJSON::encode($result);

                }

                else{

                    $result['success'] = false;

                    echo function_exists('json_encode') ? json_encode($result) : CJSON::encode($result);

                }

            }

        }

        else{

            echo $json;

        }


    }

....



как видите стандратная валидация осталась нетронутой, я в том смысле что не придется переделывать конроллеры которые были написаны ранее.

в случае удачной валидации создасться комментарий и его отрендеренное представление вернется в форму и будет вызвана функции onSubmit которая добавить комментарий в конец очереди.

Можете попробовать добавить комментарий на любой странице http://creative-territory.net/.

Есть небольшая проблема при первом сабмите говорит что контент пустой, при повторном все нормально работает. Есть предположение что это из-за CKEditor’а. Возможно придется заменить onSubmit на onAfterSubmitValidate и добавить еще onBeforeSubmitValidate, что бы как то перенести данные из CKEditor’а в соотвествующую <textarea>. Или вообще отказаться от этой затеи.

Вообщем нужны ваши комментарии, критика и прочее.

Может стоит просить что бы что то подобное добавили в официальную версию. Или кто как вообще реализовывал подобное.

Спасибо

мда…всетаки пришлось добавить onAfterSubmitValidate и onBeforeSubmitValidate. Оказалось что CKEditor заполняет соответствующую <textarea> только при нормальном сабмите. Плюс пришлось отключить validateOnChange потому как при проверке последнего поля ворма отправляла одни и теже данные два раза:

  • для валидации onChange при этом создавая запись в БД

  • и повторно, после валидации onChange, но уже как валидацию при onSubmit

вам плохо казалось, когда я решал проблему с FCK достаточно было получить все инстансы с FCK и вызвать внутренний метод FCKшкой API для того, чтобы все поля заполнились… а лезть в базовые классы, файлы и уж тем более делать там изменения - зло!!!

(удалено)

Мне казалось правильно - сам по себе CKEditor заполняет поля только при нормальном сабмите, а при AJAX именно и нужно было вызвать метод который заполнил бы все поля. А правильно его вызвать можно было бы только при собитии onSubmit.

А на счет изменений базовых классов - зло полностью перекраивать их - зло (менять имена методов, алгоритмы работы и пр.), а расширить функциональность никак не зло (хотя конечно тут возможны варианты). Некоторые мои изменения внесли в SVN, а перед тем как их внесли я должен был около 1 месяца (или больше) работать с модифицированными мною файлами. Или мне нужно было отложить работу над проектом и ждать пока внесут изменения, или полностью переписать некоторые компоненты фреймворка только для того что бы добавить одну переменную и пару строчек if????

Может быть вы знаете почему validateOnChange работает как js событие onblur? Это откровенно печалит, мне необходимо сделать так, чтобы при изменении (!именно при изменении, хотя бы одного символа, добавлении/уделении, а не изменения значения поля и вывод фокуса из него, как работает validateOnChange), происходила валидация, в соответствии с регуляркой из rules. Причина кроется тут, я уверен, файл jquery.yiiactiveform.js код:




$.each(settings.attributes, function (i, attribute) {

if (this.validateOnChange) {

$form.find('#' + this.inputID).change(function () {

validate(attribute, false);

}).blur(function () {

if (attribute.status !== 2 && attribute.status !== 3) {

validate(attribute, !attribute.status);

}

});

}



И еще одно, поделитесь, пожалуйста, рецептом создания таких же валидационных статусов, как у вас на форуме при регистрации (галочка и надпись Available/Unavaileble). По возможности ответы киньте на мыло) Буду ну ооочень признателен!