Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where should my Javascript go for View Components?

I'm getting used to view components in MVC 6, and I asked a similar question a few years ago about partial views. If I build a view component encapsulating a common use-case that requires its own Javascript, where do I put that Javascript? I know that it is dangerous at best to have Javascript in partial views, but it would be a lot simpler to include it in the view component, rather than in the containing view or a separate file that has to be referenced by the containing view.

For example, say I have a view component that has two drop-downs. The selection in the first drop-down determines what items appear in the second drop-down. This is easily handled in Javascript, of course, but where do I put it?

like image 614
AJ. Avatar asked Jan 21 '16 19:01

AJ.


1 Answers

From my experience with ASP.NET 5 View Components, I would say that the best thing to do with them is to keep them isolated and in one place, so they will be easily to manage in long-term projects.

In one of my ASP.NET projects, I've developed View Components structure like this one:

View Components structure

View, Backend code and Model are all in one place, so when you move around the folder, you are sure that you move whole component. Moreover, when you are modyfying them, you have quick access to all of their parts.

It will be convinient to put JavaScript which is highly coupled with a component also in such structure. You can do this by simply creating the file under the component's folder, and then writing a GULP TASK that will copy JS file to wwwroot. From that point, you will be able to link that JavaScript code on component's .cshtml using standard syntax:

<script src="~/Components/yourcomponent.js"></script>

To obtain such a structure in my project, I've extended Razor, to be able to search for my component's CSHTML's in proper place. To do this, I've added this code in Startup.cs:

public partial class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
       //non relevant code skipped
       services.AddMvc().AddRazorOptions(ConfigureRazor);

    }

    public void ConfigureRazor(RazorViewEngineOptions razor)
    {
        razor.ViewLocationExpanders.Add(new ViewLocationExpander());
    }
}

and the ViewLocationExpander class is:

public class ViewLocationExpander : IViewLocationExpander
{
    protected static IEnumerable<string> ExtendedLocations = new[]
    {
        "/{0}.cshtml"
    };

    public void PopulateValues(ViewLocationExpanderContext context)
    {
        //nothing here
    }

    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        //extend current view locations
        return viewLocations.Concat(ExtendedLocations);
    }
}

Then, you invoke component like this (from any .cshtml view):

@await Component.InvokeAsync("NavigationComponent",new NavigationComponentModel())
like image 140
Marcin Zablocki Avatar answered Nov 04 '22 09:11

Marcin Zablocki