In my shared layout I would like to have a "scripts" section to stuff it with all the scripts needed for page functionality.
Layout.cshtml
<html>
<head>
<title>Test</title>
<script src="#Url.Content("~/Scripts/jquery-2.0.3.js")" type="text/javascript"> </script>
#RenderSection("Scripts", required: false)
</head>
<body>
#RenderBody()
</body>
</html>
So, my view loads a specific javascript, and I want it to be in "scripts" section, and it's working.
Index.cshtml
#model PlatformaPu.Areas.Inventura.Models.Home.Index
#section Scripts {
<script src="#Url.Content("~/Areas/Inventura/Scripts/Home/Index.js")" type="text/javascript"></script>
}
{CONTENT REMOVED FOR BREVITY}
#section Footer {
#Html.Partial("~/Views/Shared/_AppSelector.cshtml", Model.AppSelector)
}
Finally, my view renders a partial and I have a javascript that this partial loads.
_AppSelector.cshtml
#model PlatformaPu.Models.Shared._AppSelector
#section Scripts {
<script src="#Url.Content("~/Scripts/Shared/_AppSelector.js")" type="text/javascript"></script>
}
{CONTENT REMOVED FOR BREVITY}
...and this is NOT working - javascript tag is NOT rendered in "scripts" section
How can I do this?
As discussed in this question, it is not possible to use sections in a partial view:
Sections don't work in partial views and that's by design. You may use some custom helpers to achieve similar behavior, but honestly it's the view's responsibility to include the necessary scripts, not the partial's responsibility. I would recommend you using the #scripts section of the main view to do that and not have the partials worry about scripts.
You should add the script reference to the main view that references the partial.
This is my first answer!
I've being working with webforms for years and now i'm dealing with MVC 5. Bit hard.
Perhaps is the wrong solution, but works :)
In Layout.cshtml. add second "ScriptsPartial" section
#RenderSection("ScriptsPartial", required: false)
In Index.cshtml, add ", new ViewDataDictionary(ViewData) { { "ViewPage", this } }"
#section Footer {
#Html.Partial("~/Views/Shared/_AppSelector.cshtml", Model.AppSelector, new ViewDataDictionary(ViewData) { { "ViewPage", this } })
}
In _AppSelector.cshtml, remove this
#section Scripts {
<script src="#Url.Content("~/Scripts/Shared/_AppSelector.js")" type="text/javascript"></script>
}
In _AppSelector.cshtml, add this in any place
#{
if (ViewData.ContainsKey("ViewPage"))
{
System.Web.Mvc.WebViewPage viewPage = (System.Web.Mvc.WebViewPage)ViewData["ViewPage"];
viewPage.DefineSection("ScriptsPartial", () =>
{
// viewPage.Write(Scripts.Render("~/AppSelector/Scripts")); // If you use a Bundle
viewPage.WriteLiteral("<script src=\"" + Url.Content("~/Scripts/Shared/_AppSelector.js") + "\" type=\"text/javascript\"></script>");
});
}
}
Just "send" the View to the PartialView (no Parent property like in WebForms?) and use it to add content to "ScriptsPartial" section.
"ScriptsPartial" is needed because DefineSection throws an error "section already defined: Scripts"
So, no more than one PartialView can use "ScriptsPartial" section... not so good solution.
Best regards,
Paco Ferre
Related
Using Razor Pages #RenderSection does not seem to be available on a Razor Page, I get "RenderSection does not exist in the current context"
I have a number of Razor pages where I am trying to use a partial page on the partial page the is some accompanying css and Javascript I would like injected into the css and script section
If I just define the sections on the partial page nothing gets rendered, so after some searching it seems that on the page using the partial you need to add RenderSection in the various sections.
Any help would be appreciated.
May be you have missed the point on usage of #RenderSection in ASP.NET Core. #RenderSection should be only in Layout page as follows:
<script src="~/lib/jquery/dist/jquery.js"></script>
#RenderSection("Scripts", required: false)
Then Razor page should be as follows:
#{
ViewData["Title"] = "My Razor Page";
Layout = "_Layout"; // If this specified in the `_ViewStart.cshtml` then you don't need it
}
<partial name="_YourPartial.cshtml"/>
#section scripts {
<script src="~/js/yourjs.js" asp-append-version="true"></script> // this is specific to this Razor page only and it will also be available on the partial view called inside this Razor Page
}
And during the generation of html, the scripts on your Razor Page will be rendered as follows:
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/js/yourjs.js" asp-append-version="true"></script>
Hope it will make you clear!
1) the below code i could write in my view to download any js or cs file at client side
<script type="text/javascript" src="~/Scripts/myScriptFile.js"></script>
OR
#Scripts.Render("~/Scripts/myScriptFile.js")
OR
<script type="text/javascript" src="#Url.Content("~/Scripts/myScriptFile.js")"></script>
then why we need to write my js code inside script section like below one?
#section Scripts{
<script type="text/javascript">
$(function () {
$("#submit1").click(function () {
alert("button");
});
});
</script>
}
2) what is the difference between the below two way to include js/css file in view ?
#Scripts.Render("~/Scripts/myScriptFile.js")
OR
<script type="text/javascript" src="#Url.Content("~/Scripts/myScriptFile.js")"></script>
Each approach will get you the same end result. In my experience, I find the approach to be more flexible and scalable as far as code maintenance goes. I'm not a fan of rendering HTML code through helpers for this reason. I hope this helps.
Is there a way to add a script tag declared in view B to the list of scripts in view A (which calls B)?
The example below should make it clear what I need.
I have a base template A:
<html>
<head>
<title>#title</title>
<!-- declared stylesheets -->
</head>
<body>
#content
<!-- Java script dependencies -->
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
</body>
</html>
Note that the base view declares dependencies to jquery.js and bootstrap.js at the end of the file. This is OK except for the following case:
#base(title) {
#header()
#navigation()
<div class="container">
#content
</div>}
The navigation view has a script tag that depends on jquery already being loaded.
When I load the page I get an error stating that "$ symbol is not defined" which makes sense because the script is parsed before jquery is loaded.
Is there a way for me to add the script declared in navigation at the end of the base view (after the declaration of jquery)?
I've tried moving the dependency to jquery to the <head></head> section and everything works as expected, but I would like to keep the current layout.
Edit: To be more clear, I want to send the script dependencies from #navigation view to #base view .
Take a look to Play's doc for moreScripts and moreStyles equivalents (last section in doc)
De dacto it deosn't need to be named scripts so you can use your own name, also you can use it for sending other blocks of HTML into higher level view (layout).
See answers to similar quesion
So it can be i.e.:
#navigationScripts = {
<script src="/assets/my-navigation.js"></script>
}
#base(title, navigationScripts) {
#header()
#navigation()
<div class="container">
#content
</div>
}
And in layout:
#(title: String, navigationScripts: Html = null)
<html>
<head>
<title>#title</title>
<!-- declared stylesheets -->
</head>
<body>
#content
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
#navigationScripts
</body>
</html>
I have some pages on my site that use certain CSS and JS resources - but they are the only page(s) to use that css or js file - so I don't want to include that CSS and JS reference in every page. Rather than modify each View to reference the CSS/JS it needs, I thought I could create a bundle in the Controller and add it to the Bundles that are already registered, and then it would be included in the bundle references, but this does not appear to be possible, or maybe I'm just going about it the wrong way.
In my Controller for a registration page for example, I thought I could write this:
Bundle styleBundle = new Bundle("~/bundles/registrationStyleBundle");
styleBundle.Include("~/Content/Themes/Default/registration.css");
BundleTable.Bundles.Add(styleBundle);
And then have this in my /Views/Shared/_Layout.cshtml:
#foreach(Bundle b in BundleTable.Bundles)
{
if (b is StyleBundle)
{
<link href="#BundleTable.Bundles.ResolveBundleUrl(b.Path)" rel="stylesheet" type="text/css" />
}
else if (b is ScriptBundle)
{
<script src="#BundleTable.Bundles.ResolveBundleUrl(b.Path)" type="text/javascript"></script>
}
}
But this does not work - the only bundles to get rendered to my page end up being the ones I specified in RegisterBundles (in /App_Start/BundleConfig.cs)
Any idea how to achieve this kind of "dynamic" or "runtime" bundling?
EDIT: Following Jasen's advice, what I ended up doing was taking the bundle creation/registration code out of the controller and adding it to RegisterBundles() in /App_Start/BundleConfig.cs. This way, the bundle is already available and the contents get minified. So:
bundles.Add(
new StyleBundle("~/bundles/registrationStyleBundle")
.Include("~/Content/Themes/default/registration.css"));
Then, in my view, I added this:
#section viewStyles{
<link href="#BundleTable.Bundles.ResolveBundleUrl("~/bundles/registrationStyleBundle")." rel="stylesheet" type="text/css" />
}
Then, in /Views/Shared/_Layout.cshtml, I added this:
#RenderSection("viewStyles", required: false)
Use the #section Scripts { } block to conditionally add bundles.
_Layout.cshtml
<body>
...
#RenderSection("Scripts", required: false)
</body>
FooView.cshtml
#section Scripts {
#Scripts.Render("~/bundles/foo")
}
KungFooView.cshtml
#section Scripts {
#Scripts.Render("~/bundles/kungfoo")
}
In my BundleConfig I typically group resources
bundles.Add(new ScriptBundle("~/bundles/Areas/Admin/js").Include(...);
bundles.Add(new StyleBundle("~/bundles/Areas/Admin/css").Include(...);
bundles.Add(new ScriptBundle("~/bundles/Areas/Home/js").Include(...);
bundles.Add(new StyleBundle("~/bundles/Areas/Home/css").Include(...);
Now I can either define multiple layout files or just selectively add bundles to the views.
I want to use CActiveForm's AjaxValidation.
My layout view file was like this before enabling AjaxValidation:
<html lang="tr-TR" dir="ltr">
<head>
<script src="<?php echo Yii::app()->request->baseUrl; ?>/js/jquery.js"></script>
</head>
As you see i'm calling jquery framework on my layout page (because i'm using on every page).
And i decided to use CActiveForm's ajax validation. Firstly enable enableAjaxValidation while calling it:
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'otel-form',
'enableAjaxValidation'=>true,
)); ?>
And then uncomment this on my controller
$this->performAjaxValidation($model);
But i got $(...).yiiactiveform is not a function error. When i check source code of page :
As you see, one more jquery library included, too. So there are 2 jquery files on page. Because of this i'm getting error. Next i put something like this for disabling jquery.
Yii::app()->clientscript->scriptMap['jquery.js'] = false;
Now jquery is loading only once. But this result is :
<html lang="tr-TR" dir="ltr">
<head>
<script type="text/javascript" src="/istanbulcityhotels/assets/cb2686c8/jquery.yiiactiveform.js"></script>
<script src="/istanbulcityhotels/js/jquery.js"></script>
</head>
jquery.yiiactiveform.js calling BEFORE jquery.js . It should called AFTER jquery.js.
It confused a bit. What should i do?
ADDITIONAL
Yes, i read this question because titles' are really similar, but question isnot same.
Thank you.
You should not be including jQuery manually from your layout. Instead of doing this, include it from within your Controller base class:
public function init() {
Yii::app()->clientScript->registerCoreScript('jquery');
}
Don't forget to call parent::init() from within your concrete controllers.
It seems CActiveForm inserts the scripts before the title tag using CClientScript::POS_HEAD constant. So a workaround is to add this code
<?php
$cs=Yii::app()->clientScript;
$cs->scriptMap=array(
'jquery.js'=>false
);?>
to the top of the main layout file in order stop it from loading jquery, then put the title tag after you load your jquery file
<script src="<?php echo Yii::app()->request->baseUrl; ?>/js/jquery.js"></script>
This way jquery.yiiactiveform.js will be loaded right after jquery.
just put your own jquery on tag title,
just like this:
<script src="/istanbulcityhotels/js/jquery.js"></script>
<title>your title</title>