Yii renderpartial (proccessoutput = true) Избегать дублирования запроса js

Im создавая сайт, который работает с ajaxRequest, когда я нажимаю ссылку, он будет загружаться с помощью ajaxRequest. Когда я загружаю, например, user/login UserController actionLogin, я renderPartial представление с processOUtput в true, поэтому js, необходимый в этом представлении, будет сгенерирован, однако, если у меня есть clientScriptRegister внутри что представление с событиями, как я могу избежать генерировать скриптRegistered дважды или несколько в зависимости от ajaxRequest? Я пробовал Yii::app()->clientScript->isSCriptRegistered('scriptId') проверить, зарегистрирован ли script, но кажется, что если вы использовали ajaxRequest, результат всегда был false, потому что он будет прав только после завершения рендеринга.

Код контроллера

if (Yii::app()->request->isAjaxRequest)
{
   $this->renderPartial('view',array('model'=>$model),false,true);
}

Просмотр кода

if (!Yii::app()->clientScript->isScriptregistered("view-script"))
   Yii::app()->clientScript->registerScript("view-script","
      $('.link').live('click',function(){
         alert('test');
     })
");

Если я впервые запрошу контроллер, он отлично работает (предупреждение 1 раз), но если я снова запрошу тот же контроллер, не обновляя мою страницу, и просто используя ajaxRequest, предупреждение выведет дважды, если вы щелкните по нему ( потому что он продолжает генерировать событие, хотя вы уже зарегистрировали его один раз)

Это то же самое, если в представлении с функцией jquery есть CActiveForm. Яркая текстовая форма corescript будет вызываться каждый раз, когда вы renderPartial.

Ответ 1

Чтобы избежать включения основных сценариев дважды

Если ваши сценарии уже включены через более ранний запрос, используйте это, чтобы не включать их снова:

// For jQuery core, Yii switches between the human-readable and minified
// versions based on DEBUG status; so make sure to catch both of them
Yii::app()->clientScript->scriptMap['jquery.js'] = false;
Yii::app()->clientScript->scriptMap['jquery.min.js'] = false;

Если у вас есть представления, которые отображаются как самостоятельно, так и как HTML-фрагменты, которые должны быть включены в AJAX, вы можете обернуть это внутри if (Yii::app()->request->isAjaxRequest), чтобы охватить все базы.

Чтобы избежать включения сценариев jQuery в два раза (решение JS)

Также существует возможность предотвращения одновременного включения сценариев на стороне клиента. Это не поддерживается напрямую и немного более громоздко, но на практике это работает нормально, и на сервере не требуется знать, что происходит на стороне клиента (то есть какие скрипты уже включены).

Идея состоит в том, чтобы получить HTML с сервера и просто вырезать теги <script> с заменой регулярных выражений. Важным моментом является то, что вы можете определить, были ли уже загружены основные сценарии и плагины jQuery (потому что они создают на нем $ или свойства) и делают это условно:

function stripExistingScripts(html) {
    var map = {
        "jquery.js": "$",
        "jquery.min.js": "$",
        "jquery-ui.min.js": "$.ui",
        "jquery.yiiactiveform.js": "$.fn.yiiactiveform",
        "jquery.yiigridview.js": "$.fn.yiiGridView",
        "jquery.ba-bbq.js": "$.bbq"
    };

    for (var scriptName in map) {
        var target = map[scriptName];
        if (isDefined(target)) {
            var regexp = new RegExp('<script.*src=".*' +
                                    scriptName.replace('.', '\\.') +
                                    '".*</script>', 'i');
            html = html.replace(regexp, '');
        }
    }

    return html;
}

Существует карта имен файлов и объектов, которые будут определены, если соответствующий script уже включен; передайте входящий HTML через эту функцию, и он проверит и удалит теги <script>, которые соответствуют ранее загруженным сценариям.

Вспомогательная функция isDefined такова:

function isDefined(path) {
    var target = window;
    var parts = path.split('.');

    while(parts.length) {
        var branch = parts.shift();
        if (typeof target[branch] === 'undefined') {
            return false;
        }

        target = target[branch];
    }

    return true;
}

Чтобы избежать добавления обработчиков событий дважды

Вы можете просто использовать объект Javascript для запоминания, если вы уже привязали обработчик; если да, не присоединяйте его снова. Например (код просмотра):

Yii::app()->clientScript->registerScript("view-script","
  window.myCustomState = window.myCustomState || {}; // initialize if not exists
  if (!window.myCustomState.liveClickHandlerAttached) {
    window.myCustomState.liveClickHandlerAttached = true;
    $('.link').live('click',function(){
       alert('test');
    })
  }
");

Ответ 2

Самый чистый способ - переопределить beforeAction(), чтобы избежать дублирования ядра script:

class Controller extends CController {

  protected function beforeAction($action) {
        if( Yii::app()->request->isAjaxRequest ) {
            Yii::app()->clientScript->scriptMap['jquery.js'] = false;
            Yii::app()->clientScript->scriptMap['jquery-2.0.0.js'] = false;
            Yii::app()->clientScript->scriptMap['anything.js'] = false;
        }

        return parent::beforeAction($action);
  }

}

Обратите внимание, что вы должны указать точное имя js файла без пути.