Javascript In Separate .js File Doese Not Render Php-Injections

Hi All,

In my View page there are a lot of Javascript code. I decided to move this Javascript to separate .js file like:


$cs = Yii::app()->getClientScript();

$cs->registerScriptFile( $baseUrl . DIRECTORY_SEPARATOR . $app_params['work_js_dir'].'/admin/tour.js' );



But the problem is, that sometimes in Javascript code I need php-injections. Say for ajax POST request I had to add parameter:


'YII_CSRF_TOKEN' : '<?php echo Yii::app()->request->csrfToken ?>'



but in this Javascript file php code is not rendered. How better to organize it ?

Depends on what injections do you need.

You can grab csrf tokens and var name from meta fields (not sure if this was introduced in Yii1 eventually, but this is the way Yii2 works). Anyway you can register metas by yourself.

If you need something more complex, you can declare a JS class in your external file, and create class instance in php code:


<!-- ... include external js... -->

<script>

var obj = new MyClassFromExternalFile({

    param1: '<?= $php_var_1 ?>',

    param2: '<?= $php_var_2 ?>'

});


obj.doStuff();

</script>

I forget to mention that is Yii 1.1.14

Please, clarify this external file must be .php file ?

Yes, I got it, I just meant that in Yii2 tokens are stored in metas, which is good.

So you can implement something similar using registerMetaTag.

Later on, you can get them this way: $(‘meta[name=csrf-token]’).prop(‘content’);

No.

If you’re storing tokens somewhere (for example in meta as I proposed before) you can add


var token = $('meta[name=csrf-token]').prop('content');

to your ‘/admin/tour.js’

and have all this stuff.

I made it, but not all works as I expect.

I run in my template:


<script type="text/javascript" src="<?php echo $baseUrl . DIRECTORY_SEPARATOR . $app_params['work_js_dir'].'/admin/category.js' ?>"></script>

<script>

	var CategoryFuncs = new CategoryFuncs({

		baseUrl : '<?php echo Yii::app()->request->baseUrl; ?>',

		YII_CSRF_TOKEN : '<?php echo Yii::app()->request->csrfToken ?>'

	});

	CategoryFuncs.Test();

</script>



and in source code of the page I see what I expect:


<script type="text/javascript" src="/testdrive/work_js/admin/category.js"></script>

<script>

	var CategoryFuncs = new CategoryFuncs({

		baseUrl : '/testdrive',

		YII_CSRF_TOKEN : 'a4ab9159a9a65b2041033e8df40a804f10b928ac'

	});

	// obj.doStuff();

	CategoryFuncs.speak();

</script>



but problem is that when I show

///////////////////////////////////////////////////////////////

Thanks, it works but not fully.

In view I init TourFuncs object:


<script type="text/javascript" src="<?php echo $baseUrl . DIRECTORY_SEPARATOR . $app_params['work_js_dir'].'/admin/tour.js' ?>"></script>

<script>

	var TourFuncs = new TourFuncs({

		tour_id : '<?php echo $tour_id; ?>',

		baseUrl : '<?php echo $baseUrl; ?>',

		YII_CSRF_TOKEN : '<?php echo Yii::app()->request->csrfToken ?>'

	});

	TourFuncs.Test();

</script>


/admin/tour.js:

function TourFuncs(Params) {

  this.tour_id = Params.tour_id;

  this.baseUrl = Params.baseUrl;

  this.YII_CSRF_TOKEN = Params.YII_CSRF_TOKEN;

  alert(  "this.YII_CSRF_TOKEN::" + var_dump(this.YII_CSRF_TOKEN)  + "     this.baseUrl::" + this.baseUrl +"   this.tour_id::" + this.tour_id  ) // ENTERED  PARAMETERS HAVE VALID VALUES

}

TourFuncs.prototype.Test = function () {

  alert("TourFuncs.prototype.Test my baseUrl is : " + this.baseUrl + "this.YII_CSRF_TOKEN::" + this.YII_CSRF_TOKEN);  // ENTERED  PARAMETERS HAVE VALID VALUES

}


...


TourFuncs.prototype.Tour_HighlightEdit = function (id) {

 alert( "Tour_HighlightEdit  id::" + id )

$("#tour_highlight_name").val('')

$("#tour_highlight_edit_dialog").dialog({

  buttons: {

    "Submit": function () {

      var tour_highlight_name = $("#tour_highlight_name").val()

      if (tour_highlight_name == "") {

        alert("Enter name !")

        $('#tour_highlight_name').focus();

        return;

      }

      var HRef = this.baseUrl + "/tour/change_tour_highlight"  // this.baseUrl = UNDEFINED

alert( "HRef::" + HRef)

      var DataArray = {

        "tour_id": this.tour_id,

        "tour_highlight_id": "",

        "name": encodeURIComponent(tour_highlight_name),

        'YII_CSRF_TOKEN': this.YII_CSRF_TOKEN                        // this.YII_CSRF_TOKEN = UNDEFINED

      };

alert( "::" + var_dump(DataArray) )

      jQuery.ajax({

        url: HRef,

        type: "POST",

        data: DataArray,

        success: onChangedTourHighlight,

        dataType: "json"

      });

    },

    "Close": function () {

      $(this).dialog("close");

    }

  },

  hide: 'slide',

  show: 'slide',

  modal: true,

  height: 520,

  width: 720

}).dialog("open");

}




The constructor of TourFuncs and method TourFuncs.Test are called during the opening of the page and they work ok.

But this page also has list of related objects, which is loaded by ajax, and loading this page button "new" is visible.

Clicking on it ajax dialog page is opened and user can enter new value( function TourFuncs.Tour_HighlightEdit is called ). When user click "Save" vars this.baseUrl and

this.YII_CSRF_TOKENare= UNDEFINED. I tried to move vars this.YII_CSRF_TOKENare before definition of class TourFuncs and it works ok.

But I do not think that is the good idea make the variables public for all file.

TL;DR

“this” in javascript is “dynamic”, it changes all the time. A common way to resolve it is to use another variable inside closure to store the value of ‘object’.


function TourFuncs(Params) {

  var that = this;

  ...

  that.someMethod = function() {

    console.log(that.YII_CSRF_TOKEN);

  }

}

Seems, that is not working. Param that is undefined…