Обновление CGridView через $.fn.yiiGridView.update

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
Ответить
WindSlasher
Сообщения: 6
Зарегистрирован: 2014.06.24, 14:35

Обновление CGridView через $.fn.yiiGridView.update

Сообщение WindSlasher »

На странице есть 2 раскрывающихся списка select и 1 грид:
1) Список профессий
2) Список предметов, соответствующих выбранной профессии
3) Грид, который содержит материалы, соответствующие выбранному предмету

Обработчик события onchange для списка профессий обновляет список предметов и грид(вызовом $.fn.yiiGridView.update('stock-grid'))
Обработчик события onchange для списка предметов обновляет грид(вызовом $.fn.yiiGridView.update('stock-grid'))

Мне нужно отфильтровать ненужные записи из грида, как только загрузится документ используя $.fn.yiiGridView.update('stock-grid').
Проблема заключается в том, что эта функция прекрасно работает внутри обработчиков событий onchange для обоих списков, но не работает перед назначением обработчиков событий(после них тоже не работает).
В консоли браузера показывается ошибка Uncaught TypeError: Cannot read property 'ajaxType' of undefined, хотя я явно присваивал свойству ajaxType корректное значение GET при инициализации виджета грида.

Весь день убил на борьбу с этой проблемой, но так и не смог найти решение. Помогите пожалуйста.

Код: Выделить всё

<?php
/* @var $this StockController */
/* @var $model Stock */

Yii::app()->clientScript->registerScript('search', "
$('.search-button').click(function(){
    $('.search-form').toggle();
    return false;
});
$('.search-form form').submit(function(){
    $('#stock-grid').yiiGridView('update', {
        data: $(this).serialize()
    });
    return false;
});
");

$this->pageTitle = 'Дистанционное обучение';
?>

<?php
// вывести flash-сообщения
    foreach(Yii::app()->user->getFlashes() as $key => $message) {
        echo '<div class="flash-' . $key . '">' . $message . "</div>\n";
    }
?>

<div class="pInsInfoBlock">
    <div class="pInsInfoBlockTitle">
        <span>Выберите профессию и предмет</span>
    </div>
    <div class="pInsInfoBlockCont">
        <ul class="pInsInfoBlockContChoose">
        
        <li>
            <div class="row">
                <?php echo CHtml::activeLabel($model,'id_profession'); ?>
                <?php echo CHtml::activeDropDownList($model,'id_profession', array(), array('id'=>'profession')); ?>
            </div>
        </li>    
        <li>
            <div class="row">
                <?php echo CHtml::activeLabel($model,'id_subject'); ?>
                <?php echo CHtml::activeDropDownList($model,'id_subject', array(), array('id'=>'subject')); ?>
            </div>
        </li>

        </ul>
    </div>
</div>

<?php

?>
<?php $this->widget('zii.widgets.grid.CGridView', array(
    'id'=>'stock-grid',
    'dataProvider'=>$modelForGrid->search($criteria),
    'filter'=>$modelForGrid,
    'ajaxType'=>'GET',
    'beforeAjaxUpdate'=>"
        function(id, options){
            var params = '';
            var id_subject;
            
            $('#subject').each(function(){
                id_subject = (this.value) ? this.value : '';
            });

            params += '&Stock[id_subject]=' + id_subject;
            
            //alert(params);
            //encodeURIComponent();
            options.data = params;
        }
    ",
    'columns'=>array(
        'title',
        array(
            'class'=>'CDataColumn',
            'header'=>'Вид материала',
            'name'=>'id_stock_type',
            'value'=>'$data->idStockType->title',
            'filter' => CHtml::activeDropDownList(
                $modelForGrid,     // model
                'id_stock_type',   // attribute 
                CHtml::listData(
                    StockType::model()->findAll(),
                    'id_stock_type',
                    'title'
                ),                    // data
                array('empty'=>'') // htmlOptions
            ),
        ),
        array(
            'class'=>'CDataColumn',
            'header'=>'Предмет',
            'name'=>'id_subject',
            'value'=>'$data->idSubject->title',
            'filter'=>'',
        ),
        'idSubject.idProfession.title',
        array(
            'class'=>'CDataColumn',
            'header'=>'Автор',
            'name'=>'idAuthor.username',
        ),

        array(
            'class'=>'CButtonColumn',
            'header'=>'Загрузка',
            'buttons'=>array(
                'download' => array(
                     'label'=>'Скачать',     // text label of the button
                     'url'=>'Yii::app()->controller->createUrl("download",array("id"=>$data->primaryKey))',
                     'imageUrl'=>Yii::getPathOfAlias('webrootRel.images.icons').'/download.png',
                )
            ),
            'template'=>'{download}',
            'deleteButtonImageUrl'=>Yii::getPathOfAlias('webrootRel.images.icons').'/delete.png',
        ),
    ),
)); ?>



<script type="text/javascript">
$(document).ready(function() {
    // Обновляет список предметов при выборе профессии
    function updateSubjects(){
        var prof = document.getElementById('profession');
        
        $.ajax({
            async: false,
            type: 'GET',
            url: '<?php echo $this->createUrl('getSubjects'); ?>',
            data: {id_profession: prof.value,},
            dataType: 'json',
            success: function (response, textStatus) {
                var prof = document.getElementById('subject');
                prof.innerHTML = '';
                
                $(response).each(function() {
                    var opt = document.createElement('option');
                    opt.value = this.id_subject;
                    opt.innerHTML = this.title;
                    prof.appendChild(opt);
                });    
            }
        });
    }

    // Получить список профессий и записать в #profession
    $.ajax({
        async: false,
        type: 'GET',
        url: '<?php echo $this->createUrl('getProfessions'); ?>',
        data: '',
        dataType: 'json',
        success: function (response, textStatus) {
            var prof = document.getElementById('profession');
            prof.innerHTML = '';
            
            $(response).each(function() {
                var opt = document.createElement('option');
                opt.value = this.id_profession;
                opt.innerHTML = this.title;
                prof.appendChild(opt);
            });    
        }
    });
    
    // Инициализация списка предметов профессии
    // alert('Инициализация списка предметов профессии');
    updateSubjects();
    
/**********************ВОТ ТУТ ПЕРЕСТАЕТ РАБОТАТЬ**********************/
    $.fn.yiiGridView.update('stock-grid'); 

    // Назначить обработчик события change для #profession
    $('#profession').change(function(){
        updateSubjects();
        $.fn.yiiGridView.update('stock-grid');
    });
    
    // Назначить обработчик события change для #subject
    $('#subject').change(function(){
        $.fn.yiiGridView.update('stock-grid');
    });
    
    
    alert('xxx');
});

</script>
IStranger
Сообщения: 36
Зарегистрирован: 2011.11.04, 10:46
Контактная информация:

Re: Обновление CGridView через $.fn.yiiGridView.update

Сообщение IStranger »

Так вы его таким же синтаксисом вызывайте, как вам CRUD сгенерировал:

Код: Выделить всё

$('#stock-grid').yiiGridView('update', {
    data: $(this).serialize()
});
Если вы его вызываете из глобального объекта $.fn.yiiGridView.update('stock-grid'), то у вас там контексты вызова разные.
Там внутри все плохо с этим))
Попробуйте просто в консоли выполнить, и посмотрите обновляет ли.
G.Azamat { Web Development / Computer simulation }
Начинающий программист думает, что в килобайте 1000 байтов, а законченный уверен, что в километре 1024 метра.
WindSlasher
Сообщения: 6
Зарегистрирован: 2014.06.24, 14:35

Re: Обновление CGridView через $.fn.yiiGridView.update

Сообщение WindSlasher »

Я пробовал такой способ. Разницы не было. Проблему решил тем, что переместил нижний блок с js кодом в Yii::app()->clientScript->registerScript(), но понятия не имею почему возникал конфликт...
IStranger
Сообщения: 36
Зарегистрирован: 2011.11.04, 10:46
Контактная информация:

Re: Обновление CGridView через $.fn.yiiGridView.update

Сообщение IStranger »

Честно говоря, не понял какой метод когда/что обновляет, скорее всего у вас аякс-запросы "пересекаются" друг с другом, либо по данным, либо по DOM-элементам.

Код: Выделить всё

updateSubjects();
$.fn.yiiGridView.update('stock-grid');
Вот эти запросы сработают параллельно и второй может запросто обогнать первый. Чтобы избегать таких неявных ошибок лучше использовать события/колбэки. Типа такого:

Код: Выделить всё

updateSubjects(function(){
     $.fn.yiiGridView.update('stock-grid');
});
А переданный в аргументе колбэк вызвать внутри вашего метода в конце success, чтобы гарантировать последовательную отработку ajax-запросов. Тогда и код станет предсказуемее и послушнее, и ошибки будет искать проще.
PS: в общем, у вас в коде куча асинхронной логики, видимо ошибка даже не в $.fn.yiiGridView.update, а параллельных вызовах $.ajax
G.Azamat { Web Development / Computer simulation }
Начинающий программист думает, что в килобайте 1000 байтов, а законченный уверен, что в километре 1024 метра.
pegas1981
Сообщения: 35
Зарегистрирован: 2012.05.15, 16:54

Re: Обновление CGridView через $.fn.yiiGridView.update

Сообщение pegas1981 »

Прошу прощения, что отвечаю в этой же теме, но возникает аналогичная ошибка как у топискстартера
Uncaught TypeError: Cannot read property 'ajaxType' of undefined
Понимаю, что проблема с пресечением AJAX-запросов, но что-то никак в голову не придет решение. Подскажите пожалуйста.

Весь код публиковать смысла нет, опишу суть с примерами.
Рендерим index.php с гридом

Код: Выделить всё

    public function actionIndex()
    {
        $model = $this->createModel();
        $rawData = $model->getAllBySelect();
        $filtersForm = new FiltersForm();
        //--------- обработчики фильтров GridView 
    $dataProvider = new CArrayDataProvider(
        //--------- настройки провайдера
    )
        
        $this->render('index', array(
            'model' => $model,
            'dataProvider' => $dataProvider,
            'filtersForm' => $filtersForm,
            'pageSize' => Yii::app()->options->params['GridViewRowCount'],
        ));
    }
 
после грида рендерится виджет первого окна диалога, который открывается при срабатывании функции create().

Код: Выделить всё

<?php
//----- вырезано
$this->widget('zii.widgets.grid.CGridView', array(
    'id' => 'planning-gridview',
    'dataProvider' => $dataProvider,
    'filter' => $filtersForm,
    'selectableRows' => $pageSize,
    'afterAjaxUpdate' => "function(id, data) {
            //----- обработчики
        }",
    'beforeAjaxUpdate' => "function(id, options) {
            //----- обработчики
        }",
    'columns' => array(
        array(
            'header' => 'Наименование',
            'name' => 'name',
            'type' => 'raw',
            'value' => '$data["name"]',
        ),
    //---- много еще колонок

?>

<?php
$this->widget('zii.widgets.jui.CJuiDialog',array(
    'id' => 'dialog',
    'options' => array(
        'autoOpen' => false,
        'resizable' => false,
        'modal' => 'true',
        'width' => '800',
        'height' => '550',
    ),
));
?>
В 1й диалог рендерится обратным запросом результат работы контроллера - представление "create"

Код: Выделить всё

    public function actionCreate()
    {
        $model = $this->createModel();
        $model->scenario = 'create';
        $model->setIsNewRecord(true);
        $isError = false;
        $postData = filter_input(INPUT_POST, get_class($model), FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY);
        if(!empty($postData)) {
            $model->attributes = $postData;
            //------ обработка данных
            if ($model->validate()) {
                $isError = false;
                //------ доп. обработка и формирование данных
                $model->save(false, $model->attributes);
            } else {
                $isError = true;
            }
        }
        

        Yii::app()->clientScript->scriptMap['jquery.js'] = false; // отключение повторной загрузки скрипта
        Yii::app()->clientScript->scriptMap['jquery-ui.js'] = false; // отключение повторной загрузки скрипта
        Yii::app()->clientScript->scriptMap['jquery-ui.min.js'] = false; // отключение повторной загрузки скрипта
        $html = $this->renderPartial('create', array(
        //-------- параметры
        ), true, true);
        echo json_encode(array('html' => $html, 'error' => $isError));
    }
 
Собственно в представлении форма плюс виджет 2го диалога, обработка которого мы опустим.

Код: Выделить всё


//--------- форма

<?php
$this->widget('zii.widgets.jui.CJuiDialog',array(
    'id' => 'dialog-second',
    'options' => array(
        'autoOpen' => false,
        'resizable' => false,
        'modal' => 'true',
        'width' => '800',
        'height' => '550',
        'open' => new CJavaScriptExpression('function() { openDialogSecond(); }'),
    ),
));
?>
После сохранении результата с формы надо обновить грид, но возникает ошибка.

Код: Выделить всё

function create() {
    var objDialog = $("#dialog");
    $.ajax({
        url: "/admin/planning/create",
        type: "post",
        dataType: "json",
        beforeSend: function(){
            var options = {
                title: "Добавить",
                buttons: {
                    "Сохранить": function() {
                        $.ajax({
                            url: "/admin/planning/create",
                            type: "post",
                            dataType: "json",
                            data: $("#planning-form").serialize(),
                            beforeSend: function(){
                                objDialog.html("Пожалуста, подождите... <div class=\"ajax-loading\"></div>");
                            },
                            success: function(data){
                                objDialog.html(data.html);
                                if (data.error === false) {
                                    objDialog.dialog("close");
                                    $.fn.yiiGridView.update("planning-gridview"); //------- здесь возникает ошибка
                                }
                            },
                        });
                    },
                    "Закрыть": function() {
                        objDialog.dialog("close");
                    }
                }
            };
            objDialog.dialog(options)
                     .dialog("open")
                     .html("Пожалуста, подождите... <div class=\"ajax-loading\"></div>");

        },
        success: function(data){
            objDialog.html(data.html);
        }
    });
    return false;
}
pegas1981
Сообщения: 35
Зарегистрирован: 2012.05.15, 16:54

Re: Обновление CGridView через $.fn.yiiGridView.update

Сообщение pegas1981 »

решение так и не найдено
Ответить