Yii CClientScript Disable RegisterScript

I though this might be useful since its not widely spread yet. There will be times when you want to disable some scripts on CClientScript so that your ajax or JSON will print properly. In this case, depending on what you want to disable, these methods might be helpful.

Disable JavaScript or CSS files in CClientScript

Well, you if want to disable JavaScript or CSS files that were included via registerCssFile or registerScriptFile you can fire the following code into your filer or anywhere your action is being fired

        $cs = Yii::app()->clientScript;
        $cs->scriptMap['jquery.js'] = false;
        $cs->scriptMap['bootstrap.min.css'] = false;
        $cs->scriptMap['bootstrap.min.js']  = false;
        $cs->scriptMap['bootstrap-yii.css'] = false;

scriptMap will disable the file mentioned (example jquery,js) and replace with 'false', this is similar to how you would go about optimizing js and css scripts on Yii as well 😉

Removing CSS or JavaScript code in CClientScript

this will be a little bit tougher than you would imagine since the array 'scripts' which suppose to be available isn't really 'public' but you can still remove the code via the following,

Yii::app()->clientScript->registerScript('mykey', "jQuery('{$selector}').{$name}({$options});");

basically, to remove the custom script i have wrote above, i will fire something like this

Yii::app()->clientScript->registerScript('mykey', false);

basically i am overwriting whatever i have registered and this will remove the custom script that i have written. Neat isn't it 😉

Remove every single custom scripts on CClientScript

if the above isn't what you were looking for, may be you are like me who manage to remove custom scripts using the above method but the script tags still appear, in this case, i fire the following code to stop my headache

        $cs = Yii::app()->clientScript;
        $cs->reset();

since we can't make 'hasScripts' to be false (which is the reason why the script tags still appear), we will reset all the calling scripts instead. but this won't always work as neat as you would want to but its a good solution so far.

Disable JavaScripts entirely on CClientScript

Well, its so irritating that i wanted everything to be disable on cclientscript, in this case, use the following,

        $cs = Yii::app()->clientScript;
        $cs->reset();
        $cs->enableJavaScript = false;

This will ensure everything is disabled.

This should be useful for people working on Ajax, restful and JSON implementation on Yii 😉

Add additional value before ajax call when using Yii CAutoComplete

If you are like me who wish to add an additional value into Yii CAutoComplete and wondering how this can be done, it is pretty simple thanks to Ron Lavie. Assuming, you have the default ajax call on your controller which is "$_GET['q']", now, you would like to get a new value to be included into your controller called "$_GET['f']" and you are wondering what to do in order to get your value into Yii CAutoComplete before it fires ajax call to your controller, this is how you should do it.

'extraParams'=>array('f'=>"js:function(){return $(\"#f\").val();}"),

Using the extraParams, we can add in additional field before an ajax call to the controller. Here's a full illustration.

      $this->widget('CAutoComplete',
          array(
             'value'=> $text,
             'name'=>'nanny_name',
             'id' => 'nanny_name',
                         //replace controller/action with real ids
             'url'=>array('/task/admin/autoCompleteNannyLookup'),
             'max'=>10, //specifies the max number of items to display
                         //specifies the number of chars that must be entered
                         //before autocomplete initiates a lookup
             'minChars'=>1,
             'delay'=>500, //number of milliseconds before lookup occurs
             'matchCase'=>false, //match case when performing a lookup?
                         //any additional html attributes that go inside of
                         //the input field can be defined here
             'htmlOptions'=>array('size'=>'40'),
             'extraParams'=>array('f'=>"js:function(){return $(\"#f\").val();}"),                                                                                   
             'methodChain'=>".result(function(event,item){\$(\"#updateValue\").val(item[1]);})",
          )); 
    ?>  

Now, whenever something is filled up on this CAutoComplete, it will search for the value in id "f" and included into variable "f" before firing up the ajax call to your controller. 🙂

How to duplicate database record in Yii with 1 line

Well this will be quick since Yii is so powerful in their active record implementation. In Yii, if you ever want to duplicate a database record, all you have to do is to issue the following line.

$model = $this->loadModel($id); // record that we want to duplicate
$mode->id = null;
$model->isNewRecord = true;
if($model->save()){
//duplicated
}

The above implementation is pretty straight forward, we load the database record into a variable called model and set its primary key to null. Next, we set the variable isNewReocord to true and save the model. Once the model is saved, you will get yourself a new duplicated data where the Id is different from the one you just loaded. (well, there's more than 1 line but the key word to this is isNewRecord =x)

How to Use Yii clientScript scriptMap to speed up your website

My pet project site was running quite slowly due to the large number of http request going and waiting for many different stylesheets and scripts that my site required to have. Certainly, there are available php script that can combine all my stylesheets and scripts into 1 big file but doing this would had already use up certain amount of resources needed to perform such compilation. Yii had already provide such method within their framework which is called scriptMap. However, scriptMap is pretty confusing and i did spend sometime figuring it out before finding it useful. Hence, writing this down would definitely serve a good purpose in the future.

What is Yii scriptMap

Yii scriptMap is a method within the clientScript class that allows you to map a particular script or stylesheet into a desirable file. It is like htaccess rule to perform redirect whenever you see a particular URL, redirect it. The same concept apply to scriptMap. Whenever you see a particular script or stylesheet, print the one that i want instead of the one you see.

How Yii scriptMap works?

I believe there are a few things to point out on Yii scriptMap before actually show you the snippet of scriptMap.

  • Yii scriptMap do not print out your stylesheet or script for you
  • Yii scriptMap doesn't work like registerScriptFile or registerCssFile (which print out your file)
  • Yii scriptMap will not map if it doesn't see the script or stylesheet you have placed on the function. Hence, you still see the same script/stylesheet.
  • Yii scriptMap directory start below the directory level of 'protected'. Hence, its at the level where you see all the css/assest/js/theme folder.
  • Please ensure the file you are mapping to, had already exist.

Once you understand the above. It is time to show you how this is being done.

Firstly, you would have to initialize the clientScript class then register all your stylesheet and script like you usual do.

$cs=Yii::app()->clientScript;
$cs->registerScriptFile(Yii::app()->request->baseUrl .'/js/html5.js');
$cs->registerCssFile(Yii::app()->request->baseUrl .'/css/reset.css');

Something like the one shown above. Once you have done that, you will see your files showing up on your site. However, these are the actual files, you want the minimized one or the one that has optimized. Therefore, you would use scriptMap as shown below,

	$cs->scriptMap=array(
		'jquery.js'=>'https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js',
		'jquery.min.js'=>'https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js',
		'html5.js'=>'/js/all.js',
		'reset.css'=>'/css/all.css'
	);

In case you are stuck here like i was, let me explain some of the more important thing above. Firstly, scriptMap is looking for the name of your script or stylesheet and NOT the path. Secondly, the file that you are mapping to (in my case its all.js and css.js). They must be created by yourself and place all the require scripting into it.

In short, if you have notice what i did with the jQuery library for my scriptMap, you would have guess what sort of functionality is scriptMap providing you. It is basically saying "if you see this name, don't show it, print the one i provide you instead :)). Cheers! Hope it helps.

Yii: How to Customize Ajax Call To Controller Without Using Native jQuery Yii Code

This is another interesting article that will definitely help many Yii developers and its community. The situation was that I wanted to use my own jQuery code to send and receives the value returned by Yii controller. However, it seems to always return me with the whole html page text. On the client side, i wasn't using any jQuery Yii code. Instead, i wrote out the logic to fit in my theme properly. The tricky part was to sent in ajax call to Yii controller. In this article, i will try to explain how this can be done without using the native jQuery Yii code. (hopefully things won't get too confusing)

Ensure Ajax Call to Controller

First thing first. We need to enable Ajax between the view and the controller. This can be easily found on google and Yii page did demonstrate a very neat way of doing this. So let's use the example one shown on Yii CActiveform page.

On the view side, we have the following code:

<?php $form = $this->beginWidget('CActiveForm', array(
    'id'=>'user-form',
    'enableAjaxValidation'=>true,
    'focus'=>array($model,'firstName'),
)); ?>

<?php echo $form->errorSummary($model); ?>

<div class="row">
    <?php echo $form->labelEx($model,'firstName'); ?>
    <?php echo $form->textField($model,'firstName'); ?>
    <?php echo $form->error($model,'firstName'); ?>
</div>
<div class="row">
    <?php echo $form->labelEx($model,'lastName'); ?>
    <?php echo $form->textField($model,'lastName'); ?>
    <?php echo $form->error($model,'lastName'); ?>
</div>

<?php $this->endWidget(); ?>

On the view side, we will need to use $this->beginWidget('CActiveForm', array(.... to create our form tag in order for ajax to work properly on your view. The $form->error is needed for the native Yii jQuery library,yiiactiveform, to be included.

On the controller, we have the following code:

public function actionCreate()
{
    $model=new User;
    $this->performAjaxValidation($model);
    if(isset($_POST['User']))
    {
        $model->attributes=$_POST['User'];
        if($model->save())
            $this->redirect('index');
    }
    $this->render('create',array('model'=>$model));
}

protected function performAjaxValidation($model)
{
    if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')
    {
        echo CActiveForm::validate($model);
        Yii::app()->end();
    }
}

Do take note of the protected function called performAjaxValidation. This is needed for you to validate through ajax. The below code is equally important for the controller to start validating through ajax call.

$this->performAjaxValidation($model);

This is all the controller needs to validate ajax calls.

Once you have your Yii ajax setup, you should be able to make ajax call using Yii native jQuery library which doesn't really give you the flexibility you need. In this case, we will have to make our own jQuery code to interact with Yii Controller.

Making Your Own jQuery Code To Send Request To Yii Controller

Now we will need to write our own jQuery code to sent request to Yii controller. From the above Yii view code, we will need to slightly alter some value so that the Yii native jQuery code library, yiiactiveform doesn't get populated. I also added an additional div block with the id 'error' so that our error can be placed in there.

<?php $form = $this->beginWidget('CActiveForm', array(
    'id'=>'user-form',
    'enableAjaxValidation'=>true,
    'focus'=>array($model,'firstName'),
)); ?>

<?php echo $form->errorSummary($model); ?>
<div id='error'></div>
<div class="row">
    <?php echo $form->labelEx($model,'firstName'); ?>
    <?php echo $form->textField($model,'firstName'); ?>
</div>
<div class="row">
    <?php echo $form->labelEx($model,'lastName'); ?>
    <?php echo $form->textField($model,'lastName'); ?>
</div>

<?php $this->endWidget(); ?>

After all the long winded talk, i shall show you how this is being done.

$(document).ready(function()
{
	$('#user-form').submit(function(event)
	{
		event.preventDefault();
		var $form = $(this);
		$.ajax({
			url: $(this).attr('action'),
			dataType: 'json',
			type: 'POST',
			data : $form.serialize()+'&ajax='+$form.attr('id'),
			success: function(data, textStatus, XMLHttpRequest)
			{
				if (data != null && typeof data == 'object'){
					$.each(data, function(key, value){
						$('#error').append(value);
					});
					
				}
			},
			error: function(XMLHttpRequest, textStatus, errorThrown)
			{

			}
		});
		return false;
	}
}

If you study jquery.yiiactiveform.js closely or saw that the controller is looking for a post key to determine an ajax call, you will notice that the reason why you are failing to get a proper json object back from the controller was because you did not append the parameter 'ajax' on to the data section, you will need to append the ajax key into it so that the controller will treat it as an ajax caller and return the appropriate json object to you instead of the return page string. And this is the reason why the below controller method is so important for this to work.

protected function performAjaxValidation($model)
{
    if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')
    {
        echo CActiveForm::validate($model);
        Yii::app()->end();
    }
}

got it? hope it helps 🙂