Yii + AJAX = Duplicate ClientScripts

Hello, I am trying to run the following command as the return of an AJAX request:


$this->controller->renderPartial($view, $params, false, true);

When you run it a few files that are already on the page is reloaded the page unnecessarily.

Does anyone know a simple way to solve this problem?

I can already prevent loading jquery for example, but the CSS files, such as the "Yii Bootstrap" for example are still loaded.

#EDIT

Please some moderator move the topic to: http://www.yiiframework.com/forum/index.php/forum/29-general-discussion-for-yii-11x/

[color="#008000"]NOTE: moved as requested[/color]

For your problem… the best solution is to not use the 4th parameter as "true"… and to register all the needed JS/CSS in the main view or at first non-ajax call…

But Yii Bootstrap CSS is added by himself on the page, there is a better solution to the problem?

Hey,

check extenstion’s code for more information about component’s configuration. Maybe setting Bootstrap::coreCss to false is what you need?

cheerio

With the setting Bootstrap::coreCss in false, the CSS does not load the page.

This is not what I want.

I want that once loaded, to make an AJAX request, it is not added unnecessarily page.

I can do this using renderPartial, but if within the return renderPartial, there is a new AJAX call, that call is not executed.

However, if I set the fourth parameter to true renderPartial, as shown above, the call is executed, but the files of "Yii Bootstrap" are added to the page again without any need.

Well, you can then check if it’s not an ajax request and register core css file manualy with Bootstrap’s public method:




if(!Yii::app()->getRequest()->getIsAjaxRequest())

    Yii::app()->bootstrap->registerCoreCss();

else

    Yii::app()->bootstrap->coreCss=false;



I liked your suggestion.

Unfortunately I took the test and failed…


class IndexAction extends CAction {

    

    public function run() {

	if (Yii::app()->request->isAjaxRequest) {

	    Yii::app()->bootstrap->coreCss = false;

	    

	    $this->controller->renderPartial('index', null, false, true);

	    Yii::app()->end();

	}

	

        $this->controller->render('index');

    }

    

}

The archives of "Yii Bootstrap" still being added to the page without making an ajax request with "ProcessOutput = true".

Hi,

ok, I wrote this code almost two years ago, but it should work now, I guess…

My version of ClientScript component caches file names in session. I haven’t use it in my recent projects, though it worked for me then. Maybe will for you, too.




class MClientScript extends CClientScript

{

	public $ajaxVar='ajax';

	public $cacheKey='__MClientScript.scriptFilesCache';

	

	/**

	 * Renders the registered scripts.

	 * This method is called in {@link CController::render} when it finishes

	 * rendering content. CClientScript thus gets a chance to insert script tags

	 * at <code>head</code> and <code>body</code> sections in the HTML output.

	 * @param string $output the existing output that needs to be inserted with script tags

	 */

	public function render(&$output)

	{

		if(!$this->hasScripts)

			return;


		$this->renderCoreScripts();


		if(!empty($this->scriptMap))

			$this->remapScripts();


		$this->unifyScripts();

		

		$request=Yii::app()->getRequest();

		if($request->getIsAjaxRequest() || $request->getParam($this->ajaxVar))//ajax request

			$this->removeSameScripts();

		else

			$this->reloadScriptsCache();

		

		$this->renderHead($output);

		if($this->enableJavaScript)

		{

			$this->renderBodyBegin($output);

			$this->renderBodyEnd($output);

		}

	}

	

	protected function removeSameScripts()

	{

		if(empty($this->scriptFiles))

			return;

		

		$scriptFiles=$this->scriptFiles;

		

		foreach($scriptFiles as $pos=>$scripts)

		{

			foreach($scripts as $file)

			{

				if($this->inCache($file))

					unset($this->scriptFiles[$pos][$file]);

			}

		}

	}

	

	protected function reloadScriptsCache()

	{

		$cache=$this->getScriptCache();

		$cache=array();

		$scriptFiles=$this->scriptFiles;

		

		foreach($scriptFiles as $pos=>$scripts)

		{

			foreach($scripts as $file)

				$this->addToCache($file);

		}

	}

	

	protected function inCache($file)

	{

		$key=crc32($file);

		$cache=$this->getScriptCache();

		return isset($cache[$key]);

	}

	

	protected function addToCache($file)

	{

		$key=crc32($file);

		$cache=$this->getScriptCache();

		$cache[$key]=$file;

		

		$session=Yii::app()->getSession();

		$session[$this->cacheKey]=$cache;

	}

	

	protected function getScriptCache()

	{

		$session=Yii::app()->getSession();

		if(!isset($session[$this->cacheKey]))

			$session[$this->cacheKey]=array();

		return $session[$this->cacheKey];

	}

}



Cheerio

drylko , thank you very much for your help, but I tested your solution here and not worked very well.

Well, the good news is that solved the problem, but to be honest I did not want to change the Core Yii Bootstrap.

Below is the steps that were made:

I added the extension NLSClientScript to the project.

Adding it, solved the problem with scripts.

Now let’s resolution CSS.

In Bootstrap.php:




// [...]


// I created a new property.


/**

 * @var boolean to register the Bootstrap in AJAX requests

 * Defaults to true.

 */

public $ajaxCssImport = true;


// [...]


// And added the following conditional

if(($this->ajaxCssImport && Yii::app()->request->isAjaxRequest) || !Yii::app()->request->isAjaxRequest ) {

    // Prevents the extension from registering scripts and publishing assets when ran from the command line.

    if (Yii::app() instanceof CConsoleApplication)

	    return;


    if ($this->coreCss !== false)

	    $this->registerCoreCss();


    if ($this->responsiveCss !== false)

	    $this->registerResponsiveCss();


    if ($this->yiiCss !== false)

	    $this->registerYiiCss();

}


if ($this->enableJS !== false)

	$this->registerCoreScripts();


// [...]



In main.php




'bootstrap' => array(

    'class' => 'ext.bootstrap.components.Bootstrap',

    'ajaxCssImport' => false,

),



With that solved my problem.

This is the solution I was looking for.

Thanks a lot Lothor

Hi Lothor,

When you use this solution, can you use js validation of CActiveForm?

Thanks in advance.