In a partial view I load a javascript file like this :
<script src="#Url.Content("~/Scripts/Testing.js")" type="text/javascript"></script>
In the Testing.js, there are some functons defined
That's work, the functions defined in the file can be used.
Now I do an action in my application, my controller return an another (where I don't load any js file) partial view. The functions defined in Testing.js are still available in this partial view.
Is there a way to "remove" the functions loaded in the first view ?
Thanks,
Update 1
I tried this in the partial view but error :
The file "~/Views/xxxx.cshtml" cannot be requested directly because it calls the "RenderSection" method.
#section MyScript {
<script src="#Url.Content("~/Scripts/Testing.js")" type="text/javascript"></script>
}
#RenderSection("MyScript", false)
You should avoid referencing any scripts in partials. You could define a section in your Layout, for example just before the closing </body> which will allow for views to include some custom scripts:
<script type="text/javascript" src="#Url.Content("~/scripts/some_common_script_that_will_be_used_by_all_views_such_as_jquery_for_example")"></script>
#RenderSection("scripts", false)
</body>
</html>
and then in the view (not in the partial view) override this section to include any scripts that this view might need:
#section scripts {
<script src="#Url.Content("~/Scripts/Testing.js")" type="text/javascript"></script>
}
Related
I have tried adding a section script inside a view component's view.
#section scripts {
<script src="~/somepath" asp-append-version="true"></script>
}
I also have the Render Section in the shared layout
#RenderSection("scripts", required: false)
When used in partial views and elsewhere in the project the script loads fine. However when in a View Component the script does not load.
I suppose I could include the script in the section tag of every view that calls the component. I feel this does not fit with the self contained nature of a view component.
Is there another way I can do this?
I also had problems with sections tag in viewcomponents. Turns out, to the best of my knowledge, there is no support for it in viewcomponents. See https://github.com/aspnet/Home/issues/2037
Jake Shakesworth has implemented a tag helper as shown in:
Javascript in a View Component
On the other hand you could just include it in your viewcomponent as an
<script defer src"...">
</script>
My requirement was to show a google map from a viewcomponent. Problem was that the script was getting called before the jquery, jquery.ui stuff.
By using defer you are telling the parser not to execute it until the document had loaded thus avoiding the problem of the having to put it in the layout for proper execution.
Defer is supported by chrome, safari, and ie(10+), ff(3.6+), o(15+)
Hope this helps
This is an example of my code:
#using MobileVet.WebApp.Services;
#inject ISettingsService SettingsService
#{
var Options = SettingsService.Value();
<!--Service Area-->
<div class="container-fluid">
<div class="row p-3">
<!--First column-->
<div class="col-md-3">
<h5 class="title">Site Navigation</h5>
<ul>
<li>Home</li>
<li>Services</li>
<li>Link 3</li>
<li>Link 4</li>
</ul>
</div>
<!--/.First column-->
<hr class="w-100 clearfix d-md-none">
<!--Second column-->
<div class="col-md-9">
<div id="map-canvas" style="min-height: 300px; min-width: 200px;">
</div>
</div>
<!--/.Second column-->
</div>
</div>
<!--Service Area-->
<script src="http://maps.google.com/maps/api/js?key=XXXXXXXXXXXXXXXXXXXXXXX&sensor=false"></script>
<script type="text/javascript" src="~/js/components/servicearea.js" defer ></script>
}
Note that you would probably need to write some logic to prevent the script to be included multiple times if the view component is present more than once on a page, which was not my case
From what I have seen, a "#section Scripts {}" in a ViewComponent is ignored and does not render in the relevant #RenderSection() of the ViewComponents _*layout.cshtml
Why that is I do not know.
#section scripts { } in viewcomponents is ignored and not rendered by Asp.Net rendering engine. So just use at the end of the view component. Also if your jquery scripts are specified at the end in your layout, then jquery will not be available in your viewcomponents. Of course moving the jquery script to the head section in layout will solve the problem but it is recommended to load the js files at the end.
So if you want to keep jquery scripts at the end of layout and still use jquery in viewcomponents, you could use javascript domcontentloaded and any jquery can be written inside domcontentloaded. Not a permanent good approach but works for me.
<script>
document.addEventListener('DOMContentLoaded', function (event) {
console.log($ === jQuery)
});
</script>
Or as mentioned by #Alberto L. Bonfiglio you could also try to move your script to another JS file and defer load it in your viewcomponent:
<script src="viewComponentScript.js" defer></script>
This is how I approached inserting scripts into a view component using Asp.net core 2.0.
First I created a partial view which I placed inside of the view components view folder.
Path: Views/Shared/Components/CalendarWidget/_CalendarScriptsPartial.cshtml
_CalendarScriptsPartial.cshtml
<environment include="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/lib/moment/moment.js"></script>
<script src="~/lib/fullcalendar/dist/fullcalendar.js"></script>
<script src="~/js/calendarWidget.js"></script>
</environment>
<environment exclude="Development">
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/moment/min/moment.min.js"></script>
<script src="~/lib/fullcalendar/dist/fullcalendar.min.js"></script>
<script src="~/js/calendarWidget.js"></script>
</environment>
Then, I brought in the scripts via the Html partial async helper method inside of my view components view.
Path: Views/Shared/Components/CalendarWidget/Default.cshtml
Default.cshtml
<section id="calendar"></section>
#await Html.PartialAsync( "Components/CalendarWidget/_CalendarScriptsPartial" )
And for the sake of completeness here is my view components class.
Path: ViewComponents/CalendarWidgetViewComponent.cs
CalendarWidgetViewComponent.cs
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace LodgersChoice.ViewComponents
{
public class CalendarWidgetViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync( )
{
return View( );
}
}
}
Note: Async isn't currently required in my example but I intend to inject a repository into the ctor of the class which will be using async/await.
Note 2: Once I'm done developing this I plan on bundling and minifying everything down to one script.
I'm registering the ViewComponents scripts in a scoped service, the registered scripts are then rendered after the scripts section in layout.
ViewComponentsService.cs
using System;
using System.Collections.Generic;
namespace YourProject.Services
{
public class ViewComponentsService
{
private readonly List<Func<object>> _scripts = new List<Func<object>>();
public IEnumerable<Func<object>> Scripts {
get {
foreach (var script in _scripts)
{
yield return script;
}
}
}
// A dictionary could be used as type for the _scripts collection.
// Doing so a script Id could be passed to RegisterScript.
// Usefull if only one script per ViewComponent type needs to be rendered.
public void RegisterScript(Func<object> script) {
_scripts.Add(script);
}
}
}
Don't forget to register the service in startup.
services.AddScoped<ViewComponentsService>();
Example ViewComponent
Here we have the ViewComponent and its scripts in the same file!
#model UI.FailUserFeedback
#inject Services.ViewComponentsService _viewComponentsService
#{
var modalId = UI.Utilities.RandomId();
var labelId = UI.Utilities.RandomId();
}
<div class="modal fade" id="#modalId" tabindex="-1" aria-labelledby="#labelId" aria-hidden="true">
#*omitted for brevity*#
</div>
#{
// the script is written here
Func<dynamic, object> RenderScript =
#<script>
(function () {
var modal = new bootstrap.Modal(document.getElementById('#modalId'));
modal.show();
})();
</script>;
// and registered here
_viewComponentsService.RegisterScript(() => RenderScript(this));
}
Layout
#inject Services.ViewComponentsService _viewComponentsService
...
#await RenderSectionAsync("Scripts", required: false)
#foreach(var script in _viewComponentsService.Scripts) {
#script();
}
In case of ViewComponent called by Controller inside a modal or another element being rendered after page is fully loaded, defer won't work either. Instead you must put these scripts in a parent View or in _Layout.
In my case it was an ajax form and
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<script src="~/lib/jquery-ajax-unobtrusive/jquery.unobtrusive-ajax.js"></script>
or even#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
would not be loaded and caused problems posting the form correctly.
View component in ASP.NET Core acts like independent view with separated controller, so you can insert bellow tag above of your view component
#{
Layout = null;
}
after that insert bellow tag to use related script,for example:
<environment include="Development">
<script src="~/js/chart.js"></script>
</environment>
<environment exclude="Development">
<script src="~/js/chart.min.js"></script>
</environment>
strong textIn my ASP MVC 5 app, I have a (master - Jquery loads here) _layout.cshtml and (child, my function sortable here, not loading) views tableView.cshtml
In the child tableView.cshtml, I've written custom JS functions that need to be invoked on Jquery Read $ ready. Since jquery has already loaded in the master page, how can I attach my function (and 3rd parts plugins) invoke it when my child page loads?
if possible, please share a modular way to attach and initialize my functions and 3rd party plugins in the childviews on the child view loading/navigation load, so that when the main jquery function loads, it also invokes my functions.
_layout.cshtml
// DOM ready is completed in master layout, I have custom JS plugin/code (sortable)
// in the child view that I need to load, when that loads
$( document ).ready(function() {
console.log( "Master layout ready, done" );
});
TableView.cshtml
// in my tableView, that inherits layout from master,
// how can I get this loaded when the page loads
(function() {
console.log( "How can I get child table plugin, loaded!" );
})();
You should make use of #RenderSection() which act as placeholders to render content from the view
You layout page might look something like
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
.....
// Include common style sheets here
#RenderSection("styles", false) // placeholder for styles
#Scripts.Render("~/bundles/modernizr")
</head>
<body>
....
#RenderBody()
....
// Include all common scripts here
#Scripts.Render("~/bundles/jquery") // include jquery first
#RenderSection("scripts", required: false) // placeholder for page specific scripts
</body>
</html>
and in the view
#model YourModel
// html here
....
#section styles {
<link href="~/Content/PageSpecificStyleSheet.css" rel="stylesheet" />
}
#section scripts {
// Add page specific scripts and plugin files here
#Scripts.Render("~/bundles/jqueryval")
<script src="../../Scripts/MyScript.js" type="text/javascript"></script>
....
<script type="text/javascript">
// Other javascript code here
</script>
}
Note #RenderSection("styles", false) is in the <head> element and #RenderSection("scripts", required: false) is immediately before the closing </body> tag meaning any scripts defined in the view will be loaded after the page elements have loaded (and after the jquery file)
What is the difference between the following 2 Javascripts? I can use the second form of Javascript in Razor engine MVC pages without any issues, so what is the benefit of using the first form?
MVC style
#section Scripts {
function check()
{
//do some validation logic here
}
}
WebForms style
<script type="text/javascript">
function check()
{
//do some validation logic here
}
</script>
The #section Scripts doesn't produce any output in the page on its own, you need to render the section somewhere. When you use it, there is a RenderSection call somewhere, like this:
<script type="text/javascript">
#RenderSection('Scripts')
</script>
The fact that the section is named Scripts doesn't have any relevance, it's just a convention that is used for sections that contain scripts.
#section Scripts { is acting like place holder for your scripts. In your layout page you would include the following
<!DOCTYPE html>
<html>
<head>
....
</head>
<body>
// common html for all pages based on this layout
#RenderSection("scripts", required: false)
</body>
This is saying, that if the page includes the section Scripts, then render it here. So your page that uses this layout might have the following
#section scripts {
#Scripts.Render("~/bundles/jqueryval")
<script src="../../Scripts/YourScript.js" type="text/javascript"></script>
<script type="text/javascript">
$('#SomeElement').click(function() {
// do something
});
</script>
}
and #RenderSection("scripts", required: false) would be replaced by whats in the #section scripts {
This may work, but won't be ideal for one reason:
#section Scripts {
function check()
{
//do some validation logic here
}
}
Will cause you to lose intellisense. It may work, but will make life more difficult. It's often best to include the script tag:
#section Scripts {
<script type="text/javascript">
function check()
{
//do some validation logic here
}
</script>
}
Also #section scripts renders where a #RenderSection("Scripts") is defined in the master page. Without it, it renders EXACTLY where the script tag you have (in your WebForms example).
I have 3 views in my MVC5 App. Say A,B,C and 3 javascript files A.js, B.js C.js
When appropriate view is loaded, I want appropriate javascript files to get loaded. I do not want all files to get loaded at the start up.
How do I achieve that?
In ViewA, add the following
#scripts {
<script src="A.js"></script>
}
In ViewB, add the following
#scripts {
<script src="B.js"></script>
}
and so on...
If you are using a _Layout.cshtml, make sure you have the proper RenderSection:
#RenderSection("scripts", required: false)
then in the views itself do this:
#section scripts {
<script src="B.js"></script>
}
I wanted to add a cusotm Script inside my partial view,the partial view will be retrieved when a user click on a paging link, but since I have included all the Jquery files inside a bundle that is referenced only inside a Script section as follow:-
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
So when I directly wrote a Script inside a partial view I got an error that Jquery is not defined , so I found a solution to directly reference the jquery file inside my partial view before ; my custom script and also before the #model IPagedList<TMS.Models.TMSServer>statement as follow:-
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#DCSort").click(function () {
//code goes here
</script>
#model IPagedList<TMS.Models.TMSServer>
<div id ="ServerTable">
So I have the following two questions:-
Is it right to directly include a refeecne to jquery insdie my partial view?
Can I write the refeecne to dynamically determine the jquery version such as <scriptsrc="~/Scripts/jquery-{version}.js">` ?
Thanks