18

Is it possible to access a Model property in an external Javascript file?

e.g. In "somescript.js" file

var currency = '@Model.Currency'; alert(currency); 

On my View

<script src="../../Scripts/somescript.js" type="text/javascript"> 

This doesn't appear to work, however if I put the javascript directly into the view inside script tags then it does work? This means having to put the code in the page all the time instead of loading the external script file like this:

@model MyModel; <script lang=, type=> var currency = '@Model.Currency'; alert(currency); </script> 

Is there any way around this?

4
  • If you could generate the external js file then their browser would cache your dynamically generated view model data. Probably not what you want? Commented Apr 25, 2012 at 10:07
  • 1
    I recently blogged about how you can [generate external JavaScript files using partial Razor views][blogpost]. The blog post shows how to use a custom action filter to parse Razor code within an external JavaScript file. tl;dr: Yes, it is possible using a simple, but clever workaround. [blogpost]: blog.mariusschulz.com/… Commented Jul 11, 2013 at 22:31
  • stackoverflow.com/a/41312348/2592042 I have explained in detail here. Commented Dec 24, 2016 at 11:45
  • @Rajshekar Reddy - none of your implementations work outside of the View page - i.e. in an external js file. Commented Feb 5, 2020 at 4:14

7 Answers 7

11

I tackled this problem using data attributes, along with jQuery. It makes for very readable code, and without the need of partial views or running static javascript through a ViewEngine. The JavaScript file is entirely static and will be cached normally.

Index.cshtml:

@model Namespace.ViewModels.HomeIndexViewModel <h2> Index </h2> @section scripts { <script id="Index.js" src="~/Path/To/Index.js" data-action-url="@Url.Action("GridData")" data-relative-url="@Url.Content("~/Content/Images/background.png")" data-sort-by="@Model.SortBy data-sort-order="@Model.SortOrder data-page="@ViewData["Page"]" data-rows="@ViewData["Rows"]"></script> } 

Index.js:

jQuery(document).ready(function ($) { // import all the variables from the model var $vars = $('#Index\\.js').data(); alert($vars.page); alert($vars.actionUrl); // Note: hyphenated names become camelCased }); 

_Layout.cshtml (optional, but good habit):

<body> <!-- html content here. scripts go to bottom of body --> @Scripts.Render("~/bundles/js") @RenderSection("scripts", required: false) </body> 
Sign up to request clarification or add additional context in comments.

Comments

9

There is no way to implement MVC / Razor code in JS files.

You should set variable data in your HTML (in the .cshtml files), and this is conceptually OK and does not violate separation of concerns (Server-generated HTML vs. client script code) because if you think about it, these variable values are a server concern.

Take a look at this (partial but nice) workaround: Using Inline C# inside Javascript File in MVC Framework

1 Comment

Thats a great solution. I can keep all of the "static" javascript in a file, and then put the "vars" part into the partial view and just load that. Nice :)
2

What you could do is passing the razor tags in as a variable.

In razor File>

var currency = '@Model.Currency'; doAlert(currency); 

in JS file >

function doAlert(curr){ alert(curr); } 

Comments

2

What i did was create a js object using the Method Invocation pattern, then you can call it from the external js file. As js uses global variables, i encapsulate it to ensure no conflicts from other js libraries. Example: In the view

 @section scripts{ <script> var thisPage = { variableOne: '@Model.One', someAjaxUrl: function () { return '@Url.Action("ActionName", "ControllerName")'; } }; </script> @Scripts.Render("~/Scripts/PathToExternalScriptFile.js") } 

Now inside of the external page you can then get the data with a protected scope to ensure that it does not conflict with other global variables in js.

 console.log('VariableOne = ' + thisPage.variableOne); console.log('Some URL = ' + thisPage.someAjaxUrl()); 

Also you can wrap it inside of a Module in the external file to even make it more clash proof. Example:

$(function () { MyHelperModule.init(thisPage || {}); }); var MyHelperModule = (function () { var _helperName = 'MyHelperModule'; // default values var _settings = { debug: false, timeout:10000, intervalRate:60000}; //initialize the module var _init = function (settings) { // combine/replace with (thisPage/settings) passed in _settings = $.extend(_settings, settings); // will only display if thisPage has a debug var set to true _write('*** DEBUGGER ENABLED ***'); // do some setup stuff // Example to set up interval setInterval( function () { _someCheck(); } , _settings.intervalRate ); return this; // allow for chaining of calls to helper }; // sends info to console for module var _write = function (text, always) { if (always !== undefined && always === true || _settings.debug === true) { console.log(moment(new Date()).format() + ' ~ ' + _helperName + ': ' + text); } }; // makes the request var _someCheck = function () { // if needed values are in settings if (typeof _settings.someAjaxUrl === 'function' && _settings.variableOne !== undefined) { $.ajax({ dataType: 'json' , url: _settings.someAjaxUrl() , data: { varOne: _settings.variableOne } , timeout: _settings.timeout }).done(function (data) { // do stuff _write('Done'); }).fail(function (jqxhr, textStatus, error) { _write('Fail: [' + jqxhr.status + ']', true); }).always(function () { _write('Always'); }); } else {// if any of the page settings don't exist _write('The module settings do not hold all required variables....', true); } }; // Public calls return { init: _init }; })(); 

2 Comments

I like this. It's simple, standard, no external library bloat. Now I can move my js code in my razor views to TypeScript in external .ts files and still access model variables. Perfect.
Im glad you like it, I also added a little more to the example for the external script. Kind of a template. That way I keep all of the scripts cached and for performance and use off the the great razor features. and I just create a Module for each partial view needed. This way it all plays together nice.
1

Try JavaScriptModel ( http://jsm.codeplex.com ):

Just add the following code to your controller action:

this.AddJavaScriptVariable("Currency", Currency); 

Now you can access the variable "Currency" in JavaScript.

If this variable should be available on the hole site, put it in a filter. An example how to use JavaScriptModel from a filter can be found in the documentation.

Comments

0

You could always try RazorJs. It's pretty much solves not being able to use a model in your js files RazorJs

Comments

0

I had the same problem and I did this:

View.

`var model = @Html.Raw(Json.Encode(Model.myModel)); myFunction(model);` 

External js.

`function myFunction(model){ //do stuff }` 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.