Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to intercept view rendering to add HTML/JS on all partial views?

I need to write the contents of a js file from a convention-driven location (like ~/ClientApp/Controllers/Home/Home.js if loading the view located at ~/Views/Home/Home.cshtml). How do I do this?

Example: if the file ~/Views/Home/Home.cshtml looks like:

<div id="some-partial-view">
   <!-- ... -->
</div>

And the file ~/ClientApp/Controllers/Home/Home.Controller.js looks like

function HomeController() {
  //some code
}

Then the rendered view returned by the webserver should look like (if using fiddler)

<!--ommitted <html> <body> tags -->

<div id="some-partial-view">
   <!-- ... -->
</div>

<script type="text/javascript">
   function HomeController() {
       //some code
   }
</script>

One way is to add an HTML Helper that will do this such as:

<div id="some-partial-view" ng:Controller="HomeController">
   <!-- ... -->
</div>
@Html.IncludeController("HomeController") 

However, i don't want to repeat this in all partial views.

Any ideas?

like image 295
leypascua Avatar asked Dec 27 '11 07:12

leypascua


People also ask

Can you put JavaScript in a partial view?

JavaScript functions can be bound to elements on the partial view; the partial view is rendered at the same time as the parent view. This happens when loading the partial view with a @Html. Action helper method, as in this section from Edit.

How do I render partial view?

Rendering a Partial View You can render the partial view in the parent view using the HTML helper methods: @html. Partial() , @html. RenderPartial() , and @html. RenderAction() .

How do you add a script section in partial view?

Add(new ScriptBundle("~/bundles/CustomScripts"). Include( "~/Scripts/Custom/partial-view. js" )); Load the custom script bundle like any other bundle in your layout.

How do you bind a model with partial view?

To create a partial view, right click on Shared folder -> select Add -> click on View.. Note: If the partial view will be shared with multiple views, then create it in the Shared folder; otherwise you can create the partial view in the same folder where it is going to be used.


1 Answers

You could write a custom view:

public class MyRazorView : RazorView
{
    public MyRazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions, IViewPageActivator viewPageActivator)
        : base(controllerContext, viewPath, layoutPath, runViewStartPages, viewStartFileExtensions, viewPageActivator)
    {

    }

    protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance)
    {
        base.RenderView(viewContext, writer, instance);

        var view = (BuildManagerCompiledView)viewContext.View;
        var context = viewContext.HttpContext;
        var path = context.Server.MapPath(view.ViewPath);
        var viewName = Path.GetFileNameWithoutExtension(path);
        var controller = viewContext.RouteData.GetRequiredString("controller");
        var js = context.Server.MapPath(
            string.Format(
                "~/ClientApp/Controllers/{0}/{0}.{1}.js",
                viewName,
                controller
            )
        );
        if (File.Exists(js))
        {
            writer.WriteLine(
                string.Format(
                    "<script type=\"text/javascript\">{0}</script>",
                    File.ReadAllText(js)
                )
            );
        }
    }
}

and a custom view engine which will return this custom view when a partial view is to be requested:

public class MyRazorViewEngine : RazorViewEngine
{
    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        return new MyRazorView(
            controllerContext, 
            partialPath, 
            null, 
            false, 
            base.FileExtensions, 
            base.ViewPageActivator
        );
    }
}

which would be registered in Application_Start:

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);

    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new MyRazorViewEngine());
}

You probably might need to adjust some of the paths as it was not quite clear in your question where exactly should the js be located but normally you should have enough details in the answer.

like image 51
Darin Dimitrov Avatar answered Nov 14 '22 02:11

Darin Dimitrov