Pass the url into ajax

Hi!

I wanna pass some URLs from my view file to JS file for further sending through ajax. And I dont know the right way to do this. I wrote something like this so far:


<script type="text/javascript">

/*<![CDATA[*/


    // Ajax urls

    aXDel = '<?php echo Yii::app()->createUrl('admin/photo/delete'); ?>';

    aXEdit = '<?php echo Yii::app()->createUrl('admin/photo/edit'); ?>';


/*]]>*/

</script>

I create two global variables in my view file, and I can access them from JS. But is there any other method?

[color="#FFFFFF"]deleted[/color]

The PHP statement should not be quoted I think:




aXDel = <?php echo Yii::app()->createUrl('admin/photo/delete'); ?>;



instead of




aXDel = '<?php echo Yii::app()->createUrl('admin/photo/delete'); ?>';



@frantic:

Your approach is fine (everything that works is a good start ;) ). You only need to make sure, you use unique global varnames. My approach here is similar to many js frameworks: I create my custom namespace using a literal object in the layout file:


<script type="text/javascript">

   var MyProjectNamespace = {};

</script>



on update i put my stuff inside this namespace:


MyProjectNamespace.someVar='asfasdf';

MyProjectNamespace.baseUrl='<?php echo Yii::app()->request->baseUrl ?>';



Optimization really depends on your application. You could e.g. also send a pure JSON response. But that requires to write more custom javascript.

@Komodo:

The quotes are required. He’s assigning a string in javascript.

Hello,

I’m using a similar method to the one described by Mike; just, in case of urls that I need to use more than once, I do prefer to pass them as a parameter to the view in my controller like:


$this->render('myview', array(

   'axEdit'=>$this->createUrl('admin/photo/edit'),

...



and then I read it as you did:


<script type="text/javascript">

/*<![CDATA[*/

...

    MyProjectNamespace.aXEdit = '<?php echo $axEdit; ?>';


/*]]>*/

</script>

bye,

Giovanni.

Okay! I gonna create the same object in layout file too. And then pass variables from the Controller like Virtual DarKness said.

Thanks to all for help! :)

Creating URLs in views is perfectly legal :) . Doing so in the controller only blows up your action code. But that’s a matter of personal taste of course.

Mike, I agree it’s a matter of taste.

I have one more idea. What do you think If don’t pass the URL at all. jQuery ajax function by default send the request to current url. We just join the correspond POST parameter to our request and then send it.

If we display photos at admin/photo/list page for example, the request will be send to PhotoController and listAction. In list action we parse the POST data and then fire the appropriate action.

For example if we send action=delete&id=100 we parse it just like:


public function actionList()

{


	if ( isset($_POST) ) {

		

		switch ( $_POST['action'] ) {

		

			case 'delete':

				$this->actionDelete();

				break;

				

			case 'edit':

				$this->actionEdit();

				break;

				

		}

		

		exit();

		

	}


	....

	// List photos here

	....

}

And the in actionEdit action we delete our photo and send the JSON response.

Anything is possible :). Personally i create an action for every ajax call (i don’t use any of the CHtml::ajax* methods at all and always use custom js). But if you can live with a single action that dispatches the request, that’s surely fine, too.

Okay I understand :)

I have one last question if you don’t mind. How do you treat the errors? I dont use CHtml::ajax too, but in this case I need to catch all possible errors myself, in controller.

For example, for edit photo action if we send id=100&name= , our action looks like:


public function actionEdit()

{


    $root = Photo::model()->findByPK($_POST['id']);

    $root->name = $_POST['name'];


    if ( !$_POST['name'] ) {

        $data['error'] = "Name can't be empty";

    }


    sleep(1);


    echo CJSON::encode($data);


    exit();


}

In js file:


$.ajax({

    url: aXEdit,

    data: xQuery,

    type: "post",

    dataType: "json",

    context: $(this),

    beforeSend: function() {

            $(this).next().show();

    },

    success: function(rs){

        if ( rs == null ) {

            // It's ok

            $(this).next().hide();

            return;

        }


        // Error

        $(this)

            .siblings('.input')

                .addClass('error')

                .val(rs.error)

                .end()

            .next()

            .hide();

    }

});

It works fine for such simple checking, but if we apply that approach for handle the registration form for example, our code will increase significantly.

That’s close to what i do. I’ve created a global “dispatchResponse” method, which handles all my ajax responses. Every response uses the same structure, similar to this:


{

   error: 'something bad happened', // only set if error

   commmand: 'bla', // a js command to execute on success

   arguments: [...] // arguments for the above command

}



Sorry, I understant what this method do not quite :)

Every AJAX call can either be successful on the server or create some sort of error condition. So i created some kind of standard format for all my json responses, no matter where the request was iniated: They all get handled by one success handler on clientside. If the response object has data.error set, i know some error happened and i can show the same nice error window on client. If everything is fine, i call the method supplied in data.command with data.arguments. So in my ajax actions all i have to do is to create this json object to tell the client, how to proceed.

This is only a rough description. Your requirements may be different so that this approach might not work for you.

Actually i’m planning a full featured AJAX framework for Yii. It will enable to build complex Ajax apps easily. But it’s too early to talk about it yet ;) .

Okay Mike, thank you) Seems I unserstand your approach, I’ll try to realize something like this :)

view form fields 2 input fields:


<script type="text/javascript">

function loadTests(){

   var patientID = $("#patientID").val();

   var roomNo    = $("#testroomNO").val();

   

   if( (patientID == "") && (roomNo == "") ){

      alert('Please select both PatientId and RoomNo');

      return false;

   }

   

   //$("#testSpan").html('<img src="'+siteUrl+'/images/ajax-loader.gif" alt="Loading Image" /> Loading...');

   $("#testSpan").html('Loading...');

   

   var ajaxUrl = "/PatientTracker/loadPatientTests";

   $.ajax({

     url: siteUrl+ajaxUrl,

     data: {

        patientId  : patientID,

        testroomNo : roomNo,

        type       : 'POST'

     },

     success: function(response){

        $("#testSpan").html(response);

     }

   });

}

</script>

controller:





   public function actionLoadPatientTests(){

      $patientId  = isset($_REQUEST['patientId'])  ? $_REQUEST['patientId']  : "";

      $testroomNo = isset($_REQUEST['testroomNo']) ? $_REQUEST['testroomNo'] : "";

      $actionType = isset($_REQUEST['type'])       ? $_REQUEST['type'] : "";

      $params     = array('patientId' => $patientId, 'testroomNo' => $testroomNo, 'actionType' => $actionType);

      

      

      //load the tests

      $condition = "t.patient_id='$patientId' AND test.test_room='$testroomNo'";

      $patientTrackers = PatientTracker::model()->with('test')->findAll($condition);

      

      $this->renderPartial('patientTests', array('patientTrackers' => $patientTrackers,

                                                 'params'=>$params));

   }