I created an application that based on ASP.NET Core .NET Framework.
I have a view and want to add javascript file on it and did as follow:
#{
ViewData["Title"] = "Index";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-backstretch/2.0.4/jquery.backstretch.min.js"></script>
<script src="~/js/app.js"></script>
<input id="greet" value="Hello!" type="button"/>
I do not add to the layout template, because it is only for view specific.
The file structure looks as follow:
My problem is, when I start the application, then the javascript file app.js does not load at all, also jquery.backstretch.min.js file.
What am I doing wrong?
Javascript
In your view
#section scripts {
<script src="~/js/app.js"></script>
}
In your layout
#RenderSection("scripts", required: false)
CSS
in your view:
#section Styles {
<link href="~/Content/contact.css" rel="stylesheet" type="text/css" />
}
In your layour
#RenderSection("styles", false)
Add the script as follows:
<script type="text/javascript" src="#Url.Content("~/js/app.js")"></script>
Browsers don't understand the meaning of ~
Related
I have an ASP.NET web application that makes use of a large Javascript file to enable front-end functionality. The issue is that since this web application is growing in size the Javascript file is growing in size along with it.
I want to remove some of my larger functions out of my main javascript file site.js and instead contain them inside a second file. My aim is to declutter the main JS file and increase readability etc.
If this were a normal web application I'm sure I'd be able to use JQuery to achieve this through use of the .getScript() however I've tried using this function to pull in a separate script with a simple alert function and I get a reference error saying that my alert function is undefined. I have included both scripts within my ASP.NET _Layout view, but still it doesn't work.
Below is what I am doing currently, what do I need to do to be able to call a JS function held inside another file from site.js?
site.js
$(function() {
$(document).ready(function() {
$.getScript("../site2.js");
sendAlert();
});
//... other js
});
site2.js
$(function() {
function sendAlert() {
alert("site2 file");
}
});
_Layout
<!DOCTYPE html>
<html>
<head>
<script src="~/js/site2.js"></script>
<script src="~/js/site.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.css" integrity="sha384-88btmYK8qOHy4Z2XuhkWZjUOHICKYe1eSDMwaDGOAy802OCu6PD6mwqY5OwnfGwp" crossorigin="anonymous">
<script defer src="https://use.fontawesome.com/releases/v5.1.0/js/all.js" integrity="sha384-3LK/3kTpDE/Pkp8gTNp2gR/2gOiwQ6QaO7Td0zV76UFJVhqLl4Vl3KL1We6q6wR9" crossorigin="anonymous"></script>
</head>
<body>
#RenderBody()
#RenderSection("Scripts", required: false)
</body>
</html>
I think that you can do this:
$(function() {
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", "../site2.js");
document.getElementsByTagName("head")[0].appendChild(script);
});
Cheers - Vinh
I am setting up an architecture for an MVC6 app, and I'm relying heavily on ViewComponents. My goal is to let each ViewComponent have its own javascript section, but from reading here rendersection does not work with ViewComponents so I've been trying to do it in another way.
In my _Layout.cshtml
I have this part in just before the closing of the body tag:
#{Html.RenderPartial("_LayoutScriptsPartial"); }
In _LayoutScriptsPartial
<environment names="Development">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/js/app.js" asp-append-version="true"></script>
</environment>
<environment names="Staging,Production">
<script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.2.0.min.js"
asp-fallback-src="~/lib/jquery/dist/jquery.min.js">
</script>
<script src="~/js/app.min.js" asp-append-version="true"></script>
</environment>
Now in one of my components at /Views/Shared/Components/MyComponent/Default.cshtml I reference another partial view that has this content, it's for a carousel ViewComponent
#model MyProj.MyViewModel
#{Html.RenderPartial("_LayoutScriptsPartial"); }
#if (!string.IsNullOrEmpty(Model.ImageUrl))
{
<script type="text/javascript">
var cssClass= "#Model.cssClass";
var imageUrl = "#Model.ImageUrl";
webbCore.carouselSetBackgroundImage(cssClass, imageUrl);
</script>
}
Only reason I had to do this was to have all required js files available for my view component.
As you can see, I reference _LayoutScriptsPartial multiple times. When I debug using chromes f12 and watching the network section, I do not se the same javascript files being downloaded multiple times. Still I have a bad feeling about this solution. I have looked around and have not found any good solutions for working with js files and ViewComponents that I really liked. Something like this would suit my needs.
My question: how good is this solution, whats the pros and cons and are there any better ways to work with js files and ViewComponents?
There are 3 main cases for an ideal solution to your problem:
ViewComponent is added 0 times and the corresponding JavaScript library is added 0 times
ViewComponent is added 1 time, the corresponding JavaScript library is added 1 time and the dynamically created initialization JavaScript is created once and placed after the library.
ViewComponent is added many times, the corresponding JavaScript library is added 1 time and the dynamically created initialization JavaScript is created for each ViewComponent and are all placed after the library.
So in your example, jquery and app.js are your libraries while your dynamically created initialization JavaScript is the part that references #Model in your <script type="text/javascript"> tag. Let's say we added your component to a view 3 times (I'll replace #RenderBody() with the resulting html from a view that invokes your component 3 times):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>#ViewData["Title"] - MyProj.Web</title>
<environment names="Development,Staging,Production">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/lib/font-awesome/css/font-awesome.css" />
<link rel="stylesheet" href="~/css/site.css" />
<link rel="stylesheet" href="~/css/culture-flags.css" />
</environment>
</head>
<body>
<header>#Html.Partial("~/Views/Shared/_Header.cshtml")</header>
<main>
<nav></nav>
<article>
<div class="container body-content">
<!--#RenderBody()-->
<!--#await Component.InvokeAsync("MyComponent", new MyViewModel {cssClass="t1", ImageUrl="1.jpg"})-->
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/js/app.js" asp-append-version="true"></script>
<script type="text/javascript">
var cssClass= "t1";
var imageUrl = "1.jpg";
webbCore.carouselSetBackgroundImage(cssClass, imageUrl);
</script>
<!--#await Component.InvokeAsync("MyComponent", new MyViewModel {cssClass="t2", ImageUrl="2.jpg"}) -->
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/js/app.js" asp-append-version="true"></script>
<script type="text/javascript">
var cssClass= "t2";
var imageUrl = "2.jpg";
webbCore.carouselSetBackgroundImage(cssClass, imageUrl);
</script>
<!--#await Component.InvokeAsync("MyComponent", new MyViewModel {cssClass="t3", ImageUrl="3.jpg"}) -->
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/js/app.js" asp-append-version="true"></script>
<script type="text/javascript">
var cssClass= "t3";
var imageUrl = "t3.jpg";
webbCore.carouselSetBackgroundImage(cssClass, imageUrl);
</script>
</div>
</article>
<aside></aside>
</main>
<footer>#Html.Partial("~/Views/Shared/_Footer.cshtml")</footer>
<!-- These are the libraries that should only be loaded once -->
<environment names="Development,Staging,Production">
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
</environment>
<!-- Ideally this is where the dynamically create scripts would go -->
#RenderSection("scripts", required: false)
</body>
</html>
As you can see, you would be loading the jquery library 4 times, once for your Layout and 3 times for your ViewComponents. Any good browser should only download the file once but will be loaded into memory multiple times and will just overwrite the the same global variables multiple times($ for example).
You might also be tempted to move the library to the top of the Layout and remove the references from the View Component but that is not a best practice either.
The main issue is that section doesn't work with ViewComponents and that appears to be by design. You should think of a ViewComponent as a fancy html helper. I haven't seen any great solutions to this problem but here are a couple of ideas.
Within the View, immediately after you call your component (Component.InvokeAsync("MyComponent")), add your javascript to #section scripts {...}
Create a library js that initializes this component and set data attributes from the element
$(".carousel").each(function() {
var css = $(this).data("carousel-css");
var image = $(this).data("carousel-image");
});
<input class="carousel" type=hidden data-carousel-css="#Model.cssClass" data-carousel-image="#Model.imageURL" />
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 a javascript file that I have included in _ViewStart.cshtml like below but I want it to append in the end of view.
#if (!Request.Browser.IsMobileDevice)
{
<script type="text/javascript" src="#Url.Content("~/scripts/example.js")"></script>
}
There is no layout to the view if its ajax call and there are alot of views which I will have to change if there is not simple way of appending this js file in the end of view.
If you don't currently have a layout for mobiles then you could introduce a new layout:
_Layout.Mobile.cshtml:
#RenderBody()
<script type="text/javascript" src="#Url.Content("~/scripts/example.js")"></script>
MVC4 will recognise the .Mobile part of the layout name and use that for mobile devices.
And then your _ViewStart.cshtml will simply be:
#{ Layout = "~/Views/Shared/_Layout.cshtml"; }
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>
}