0

Apologies if I'm using the wrong terminology, I'm fairly new to this technology.

I have a view which we'll call MainView.cshtml:

<div>
  @RenderPartial("_Partial");
</div>

<script type="text/javascript">
 $(document).ready(function() {
    someFunctionDefinedIn_Partial();
 }
</script>

The _Partial view has javascript that defines a function (in this case someFunctionDefinedIn_Partial.

function someFunctionDefinedIn_Partial()
{
  // This uses the "@" syntax to access C# variables, which can be done in .cshtml
  alert("Hello. This variable is from C#: @ClassInCSharp.Variable");
}

When I run the code above I'm told in the chrome console that the function someFunctionDefinedIn_Partial doesn't exist. I'm guessing this is because javascript in a partial doesn't make its way out to the container.

I looked around a bit and found that I can extract the javascript to its own .js file and reference that as shown in this SO post: How to render JavaScript into MasterLayout section from partial view?

However, the post above suggests extracting javascript into its own separate file .js. If I do this, then I am using "raw" javascript, so I can't use the @ notation to reference variables from my C#.

Is it possible to somehow include javascript in my MainView.cshtml which also has access to the @ syntax so I can use C# methods/variables? If not, is it possible to create an external javascript file, but have it be a .cshtml file so I can use the "@" syntax?

6
  • You can use Razor @ notation to output variables for JS. Commented Dec 1, 2017 at 17:25
  • Is the variable you're accessing in C# available in your MainView? Or is it only accessible to the partial? Commented Dec 1, 2017 at 17:27
  • In this case the variable is assumed to be accessible to both. Commented Dec 1, 2017 at 17:28
  • @VictorChelaru Oh, well then just pull the javascript from the partial out into MainView.cshtml. In general, partials should not contain logic that depends on specific variables available in the environment. The entire idea of a partial is that it can be loaded anywhere. So if you expect a C# variable in your partial, it may be available one place you include it, and unavailable in another, causing an error. Commented Dec 1, 2017 at 17:30
  • @VictorChelaru It is also worth mentioning that pulling the javascript out of your partial and into your MainView.cshtml means that you don't have to pollute the global javascript scope with functions. You can define them inside of the document.ready function in your MainView, and then they are local to that function. Commented Dec 1, 2017 at 17:31

2 Answers 2

1

Can I use Javascript (with @ syntax) from partial into the main view?

Yes, but the order of javascript operations is very important. Strictly speaking, the following javascript code should error out:

console.log(myvariable);
var myvariable = "hello world!";

I'm using a variable before it's defined. That is the similar problem you are having.

Would I recommend using Javascript directly inside a view?

Definitely almost exclusively never. The way most javascript/css/html is written today is tightly coupled enough. Adding a coupling to C# seems like a giant code smell. My personal preference is to add data to html elements and have the javascript only coupled to my html. So instead of :

<script>
var myIds = [@(string.Join(Model.People.Select(p => Id.ToString().ToArray(), ",")];
</script>

Which is just insanely ugly and hard to debug, I apply my values to the html presentation that is representing my object:

<div data-id="@model.Id" class="person">
  Person Name: @Html.DisplayFor(m => m.name)
</div>

<script>
var myIds = [];
$('.person').each((i,p) => myIds.push($(p).data("Id"));
</script>

Now I can't really make a mistake about making sure the Id's in my array are the same ones on the page, everything is encapsulated together.

The other code smell is using @() methods in a view for logic. For example, I see a lot of:

@foreach(var person in Model.persons) 
{
  if (person.Age >= 21)
  {
    <div>Adult</div>
  }
  else
  {
    <div>Child</div>
  }
}

To me, that is logic in a view. My definition of a ViewModel is a model that represents all the necessary data-points (even those derived from logic). So I would do something like:

public class PersonVM
{
  public DateTime BornOn { get; set; }
  public bool IsAdult { get { return /*BornOnLogic*/; } ]
}

So in my view, I don't understand why anyone would need to use any C# directly within Javascript.

I would also recommend reading Philip Walton's (Google Engineer) -Decoupling Your HTML, CSS, and JavaScript.

Sign up to request clarification or add additional context in comments.

10 Comments

Not cluttering your DOM would be one reason. Sending entire models through (especially to angularjs) is extremely beneficial. Your data-id example can be tampered with by the user as well. They can change those values in the DOM before the JS runs, allowing access to edit/delete/etc. users with IDs they are not supposed to. Using an obfuscated IIFE that takes in the values from razor directly is much more secure. Not to say that this should be done every time, but there definitely are legitimate use cases
Yes it was in fact an order of. I had defined my JS in the main view prior to the Html.RenderPartial. If I move the main view JS to be after the RenderPartial call, all works well.
@mhodges cluttering the DOM sure, but that argument is a wash when it comes to maintainability and re-sure VS javascript in a view. As for sending a model, security argument, nothing from the client can be assume to be clean regardless of how it's sent down to the client. No technology (raw javascript, knockout, redux, react, angular) is secure in terms of keeping a model valid. The National Institute of Standards and Technology (NIST) in the United States specifically recommends against this practice
On a side-note, building your JavaScript data from your views is an old way of thinking about building views. Post-angular, react, etc. it is exactly the opposite. You should build your views from your JavaScript data. It is much faster, much more secure, and much more reliable. Never trust your HTML, it is way too easy to manipulate.
@mhodges much more? How hard is it to pause javascript execution and either change a dom element or change script in chrome memory? About the same amount of effort (i've done both), they're both ridiculously easy. Changing a json resposne is also brain dead easy.
|
0

I don't recommend you to include JS in a Partial view, as it can be added many times in a given view. Take a look at link

I suggest you to move the partials JS to the main view.

UPDATE

If you don't have any other option, consider that Razor cannot be used in plain JS: Link

What you can do is to extract the C# values needed in your JS and send them when invoking the JS. So you could have:

function someFunctionDefinedIn_Partial(variableValue)
{
  // This uses the "@" syntax to access C# variables, which can be done in .cshtml
  alert("Hello. This variable is from C#: " + variableValue);
}

And invoke it from the partial view:

someFunctionDefinedIn_Partial(@ClassInCSharp.Variable);

1 Comment

Thanks for the suggestion, but the original question is not "should I?" but rather "how do I?"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.