Как перехватить рендеринг вида, чтобы добавить HTML/JS на все частичные виды?
Мне нужно записать содержимое файла js из места, управляемого конвенциями (например, ~/ClientApp/Controllers/Home/Home.js, если загружается представление, расположенное в ~/Views/Home/Home.cshtml). Как мне это сделать?
Пример: если файл ~ / Views / Home / Home.cshtml выглядит так:
<div id="some-partial-view">
<!-- ... -->
</div>
И файл ~/ClientApp/Controllers/Home/Home.Controller.js выглядит так
function HomeController() {
//some code
}
Тогда отображаемое представление, возвращаемое веб-сервером, должно выглядеть следующим образом (при использовании fiddler)
<!--ommitted <html> <body> tags -->
<div id="some-partial-view">
<!-- ... -->
</div>
<script type="text/javascript">
function HomeController() {
//some code
}
</script>
Одним из способов является добавление помощника HTML, который сделает это, например:
<div id="some-partial-view" ng:Controller="HomeController">
<!-- ... -->
</div>
@Html.IncludeController("HomeController")
Однако я не хочу повторять это во всех частичных взглядах.
Есть идеи?
2 ответа
Вы можете написать собственный вид:
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)
)
);
}
}
}
и механизм пользовательского представления, который будет возвращать этот пользовательский вид при запросе частичного представления:
public class MyRazorViewEngine : RazorViewEngine
{
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
return new MyRazorView(
controllerContext,
partialPath,
null,
false,
base.FileExtensions,
base.ViewPageActivator
);
}
}
который будет зарегистрирован в Application_Start
:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MyRazorViewEngine());
}
Возможно, вам придется скорректировать некоторые пути, так как в вашем вопросе не совсем ясно, где именно должны располагаться js, но обычно у вас должно быть достаточно деталей в ответе.
Было бы более разумно включить все ваши javascript в внешнее кольцо, а затем включить его через index.php или где-нибудь еще...
Лично я использую jQuery и включаю каждый объект примерно так...
//View Objects
(function($){
var views = {
init: function()
{
this.view1();
this.view2();
},
view1 : function()
{
// I am
},
view2 : function()
{
// all yours
}
}
//call/invoke my view objects
$(function(){
//call view object via init()
view.init();
});
})(jQuery);