[javascript] How to set javascript variables using MVC4 with Razor

Can someone format the code below so that I can set srcript variables with c# code using razor?

The below does not work, i've got it that way to make is easy for someone to help.

@{int proID = 123; int nonProID = 456;}

<script type="text/javascript">
    @{

     <text>  

    var nonID =@nonProID;
    var proID= @proID;
    window.nonID = @nonProID;
    window.proID=@proID;

    </text>
}
</script>

I am getting a design time error

enter image description here

This question is related to javascript c# asp.net-mvc asp.net-core .net-core

The answer is


You should take a look at the output that your razor page is resulting. Actually, you need to know what is executed by server-side and client-side. Try this:

@{
    int proID = 123; 
    int nonProID = 456;
}

<script>

    var nonID = @nonProID;
    var proID = @proID;
    window.nonID = @nonProID;
    window.proID = @proID;

</script>

The output should be like this:

enter image description here

Depending what version of Visual Studio you are using, it point some highlights in the design-time for views with razor.


I use a very simple function to solve syntax errors in body of JavaScript codes that mixed with Razor codes ;)

function n(num){return num;}

var nonID = n(@nonProID);
var proID= n(@proID);

@{
int proID = 123; 
int nonProID = 456;
}

<script>

var nonID = '@nonProID';
var proID = '@proID';
window.nonID = '@nonProID';
window.proID = '@proID';

</script>

I've been looking into this approach:

function getServerObject(serverObject) {
  if (typeof serverObject === "undefined") {
    return null;
  }
  return serverObject;
}

var itCameFromDotNet = getServerObject(@dotNetObject);

To me this seems to make it safer on the JS side... worst case you end up with a null variable.


This sets a JavaScript var for me directly from a web.config defined appSetting..

var pv = '@System.Web.Configuration.WebConfigurationManager.AppSettings["pv"]';

I found a very clean solution that allows separate logic and GUI:

in your razor .cshtml page try this:

<body id="myId" data-my-variable="myValue">

...your page code here

</body>

in your .js file or .ts (if you use typeScript) to read stored value from your view put some like this (jquery library is required):

$("#myId").data("my-variable")

This should cover all major types:

public class ViewBagUtils
{
    public static string ToJavascriptValue(dynamic val)
    {
        if (val == null) return "null";
        if (val is string) return val;
        if (val is bool) return val.ToString().ToLower();
        if (val is DateTime) return val.ToString();
        if (double.TryParse(val.ToString(), out double dval)) return dval.ToString();

        throw new ArgumentException("Could not convert value.");
    }
}

And in your .cshtml file inside the <script> tag:

@using Namespace_Of_ViewBagUtils
const someValue = @ViewBagUtils.ToJavascriptValue(ViewBag.SomeValue);

Note that for string values, you'll have to use the @ViewBagUtils expression inside single (or double) quotes, like so:

const someValue = "@ViewBagUtils.ToJavascriptValue(ViewBag.SomeValue)";

This is how I solved the problem:

@{int proID = 123; int nonProID = 456;}

<script type="text/javascript">
var nonID = Number(@nonProID);
var proID = Number(@proID);
</script>

It is self-documenting and it doesn't involve conversion to and from text.


Note: be careful to use the Number() function not create new Number() objects - as the exactly equals operator may behave in a non-obvious way:

var y = new Number(123); // Note incorrect usage of "new"
var x = new Number(123);
alert(y === 123); // displays false
alert(x == y); // displays false

One of the easy way is:

<input type="hidden" id="SaleDateValue" value="@ViewBag.SaleDate" />
<input type="hidden" id="VoidItem" value="@Model.SecurityControl["VoidItem"].ToString()" />

And then get the value in javascript:

var SaleDate = document.getElementById('SaleDateValue').value;
var Item = document.getElementById('VoidItem').value;

Since razor syntax errors can become problematic while you're working on the view, I totally get why you'd want to avoid them. Here's a couple other options.

<script type="text/javascript">
    // @Model.Count is an int
    var count = '@Model.Count';
    var countInt = parseInt('@Model.ActiveLocsCount');
</script>

The quotes act as delimiters, so the razor parser is happy. But of course your C# int becomes a JS string in the first statement. For purists, the second option might be better.

If somebody has a better way of doing this without the razor syntax errors, in particular maintaining the type of the var, I'd love to see it!


It works if you do something like this:

var proID = @proID + 0;

Which produces code that is something like:

var proID = 4 + 0;

A bit odd for sure, but no more fake syntax errors at least. Sadly the errors are still reported in VS2013, so this hasn't been properly addressed (yet).


Not so much an answer as a cautionary tale: this was bugging me as well - and I thought I had a solution by pre-pending a zero and using the @(...) syntax. i.e your code would have been:

var nonID = 0@(nonProID);
var proID = 0@(proID);

Getting output like:

var nonId = 0123;

What I didn't realise was that this is how JavaScript (version 3) represents octal/base-8 numbers and is actually altering the value. Additionally, if you are using the "use strict"; command then it will break your code entirely as octal numbers have been removed.

I'm still looking for a proper solution to this.


I've seen several approaches to working around the bug, and I ran some timing tests to see what works for speed (http://jsfiddle.net/5dwwy/)

Approaches:

  1. Direct assignment

    In this approach, the razor syntax is directly assigned to the variable. This is what throws the error. As a baseline, the JavaScript speed test simply does a straight assignment of a number to a variable.

  2. Pass through `Number` constructor

    In this approach, we wrap the razor syntax in a call to the `Number` constructor, as in `Number(@ViewBag.Value)`.

  3. ParseInt

    In this approach, the razor syntax is put inside quotes and passed to the `parseInt` function.

  4. Value-returning function

    In this approach, a function is created that simply takes the razor syntax as a parameter and returns it.

  5. Type-checking function

    In this approach, the function performs some basic type checking (looking for null, basically) and returns the value if it isn't null.

Procedure:

Using each approach mentioned above, a for-loop repeats each function call 10M times, getting the total time for the entire loop. Then, that for-loop is repeated 30 times to obtain an average time per 10M actions. These times were then compared to each other to determine which actions were faster than others.

Note that since it is JavaScript running, the actual numbers other people receive will differ, but the importance is not in the actual number, but how the numbers compare to the other numbers.

Results:

Using the Direct assignment approach, the average time to process 10M assignments was 98.033ms. Using the Number constructor yielded 1554.93ms per 10M. Similarly, the parseInt method took 1404.27ms. The two function calls took 97.5ms for the simple function and 101.4ms for the more complex function.

Conclusions:

The cleanest code to understand is the Direct assignment. However, because of the bug in Visual Studio, this reports an error and could cause issues with Intellisense and give a vague sense of being wrong.

The fastest code was the simple function call, but only by a slim margin. Since I didn't do further analysis, I do not know if this difference has a statistical significance. The type-checking function was also very fast, only slightly slower than a direct assignment, and includes the possibility that the variable may be null. It's not really practical, though, because even the basic function will return undefined if the parameter is undefined (null in razor syntax).

Parsing the razor value as an int and running it through the constructor were extremely slow, on the order of 15x slower than a direct assignment. Most likely the Number constructor is actually internally calling parseInt, which would explain why it takes longer than a simple parseInt. However, they do have the advantage of being more meaningful, without requiring an externally-defined (ie somewhere else in the file or application) function to execute, with the Number constructor actually minimizing the visible casting of an integer to a string.

Bottom line, these numbers were generated running through 10M iterations. On a single item, the speed is incalculably small. For most, simply running it through the Number constructor might be the most readable code, despite being the slowest.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to c#

How can I convert this one line of ActionScript to C#? Microsoft Advertising SDK doesn't deliverer ads How to use a global array in C#? How to correctly write async method? C# - insert values from file into two arrays Uploading into folder in FTP? Are these methods thread safe? dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Best way to "push" into C# array

Examples related to asp.net-mvc

Using Lato fonts in my css (@font-face) Better solution without exluding fields from Binding Vue.js get selected option on @change You must add a reference to assembly 'netstandard, Version=2.0.0.0 How to send json data in POST request using C# VS 2017 Metadata file '.dll could not be found The default XML namespace of the project must be the MSBuild XML namespace How to create roles in ASP.NET Core and assign them to users? The model item passed into the dictionary is of type .. but this dictionary requires a model item of type How to use npm with ASP.NET Core

Examples related to asp.net-core

dotnet ef not found in .NET Core 3 How to use Bootstrap 4 in ASP.NET Core ASP.NET Core - Swashbuckle not creating swagger.json file Getting value from appsettings.json in .net core .net Core 2.0 - Package was restored using .NetFramework 4.6.1 instead of target framework .netCore 2.0. The package may not be fully compatible Automatically set appsettings.json for dev and release environments in asp.net core? Get ConnectionString from appsettings.json instead of being hardcoded in .NET Core 2.0 App Unable to create migrations after upgrading to ASP.NET Core 2.0 EF Core add-migration Build Failed ASP.NET Core form POST results in a HTTP 415 Unsupported Media Type response

Examples related to .net-core

dotnet ef not found in .NET Core 3 HTTP Error 500.30 - ANCM In-Process Start Failure Assets file project.assets.json not found. Run a NuGet package restore Is ConfigurationManager.AppSettings available in .NET Core 2.0? How to update record using Entity Framework Core? Using app.config in .Net Core EF Core add-migration Build Failed Build .NET Core console application to output an EXE What is the difference between .NET Core and .NET Standard Class Library project types? Where is NuGet.Config file located in Visual Studio project?