This question is related to
Django: Best Way to Add Javascript to Custom Widgets
But is not the same.
The original question asks how to add supporting javascript to a custom django widget, and the answer is to use forms.Media, but that solution does not work for me. My example is this:
The widget, when rendered in a form, creates a line which looks like (toy example) this:
<div id="some-generated-id">Text here</div>
Now, what I also want to add to the output is another line looking like this:
<script>
$('#some-generated-id').datetimepicker(some-generated-options)
</script>
The initial idea is that when the widget is rendered, both the div and script get rendered, but that does not work. The problem is that the structure of the html document looks like:
-body
- my widget
- my widget's javascript
-script
-calls to static files (jQuery, datetimepicker,...)
At the time the widget's javascript code is loaded in the browser, jQuery and datetimepicker js files have not yet been loaded (they load at the end of the document).
I cannot do this using Media, since the options and id I generate are vital to the function. What is the best way to solve this?
From the docs:
The order in which assets are inserted into the DOM is often important. For example, you may have a script that depends on jQuery. Therefore, combining Media objects attempts to preserve the relative order in which assets are defined in each Media class.
Consider this example:
class FooWidget(forms.TextInput):
class Media:
js = ('foo.js',)
class BarWidget(forms.TextInput):
class Media:
js = ('bar.js',)
class SomeForm(forms.Form):
field1 = forms.CharField(widget=BarWidget)
field2 = forms.CharField(widget=FooWidget)
def __init__(self, *args, **kwargs):
super(SearchForm, self).__init__(*args, **kwargs)
Now when you call form.media, the scripts will render like this:
<script type="text/javascript" src="/static/bar.js"></script>
<script type="text/javascript" src="/static/foo.js"></script>
Why does bar.js render before foo.js? Because django renders them based on the order they were called on in the form, not the order that the classes were defined in. If you want to change the order in this example, simply swap the position field1 and field2 in SomeForm.
How does this help you with jQuery? You can render your jQuery CDN script via your custom widget:
class FooWidget(forms.TextInput):
class Media:
js = ('https://code.jquery.com/jquery-3.4.1.js', 'foo.js',)
class BarWidget(forms.TextInput):
class Media:
js = ('https://code.jquery.com/jquery-3.4.1.js', 'bar.js',)
Now your form.media will look like this:
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script type="text/javascript" src="/static/bar.js"></script>
<script type="text/javascript" src="/static/foo.js"></script>
Notice how /static/ wasn't appended to the jQuery CDN? This is because the .media attribute checks whether the given filepaths contain http or https, and only appends your STATIC_URL setting to filepaths that are relative.
Also note that duplicate file names are automatically removed, so I would say it's good practice to include a https://code.jquery.com/jquery-3.4.1.js at the beginning of every widget that requires it. That way, no matter what order you render them in, the jQuery script will always appear before files that need it.
On a side note, I would be careful when including numbers in your filenames. As Django 2.2 there appears to be a bug when trying to order the scripts.
For example:
class FooWidget(forms.TextInput):
class Media:
js = ('foo1.js', 'foo2.js',)
class BarWidget(forms.TextInput):
class Media:
js = ('bar1.js', 'bar13.js',)
class SomeForm(forms.Form):
field1 = forms.CharField(widget=BarWidget)
field2 = forms.CharField(widget=FooWidget)
def __init__(self, *args, **kwargs):
super(SearchForm, self).__init__(*args, **kwargs)
Will look like:
<script type="text/javascript" src="/static/bar1.js"></script>
<script type="text/javascript" src="/static/foo1.js"></script>
<script type="text/javascript" src="/static/bar13.js"></script>
<script type="text/javascript" src="/static/foo2.js"></script>
I've tried various combinations of names containing numbers, and I can't follow the logic, so I assume this is a bug.
Since the JavaScript is an inline script, you will need to use a the native DOMContentLoaded event to wait for the jQuery to load.
<script>
window.addEventListener('DOMContentLoaded', function() {
(function($) {
$('#some-generated-id').datetimepicker(some-generated-options);
})(jQuery);
});
</script>
Alternately, if you can put your code into an external script file, you can use the defer attribute of the script tag.
<script src="myfile.js" defer="defer"></script>
See the MDN.
You want to execute some plugin script on added div. You need to add class to your element and associate a custom event to class. Which will execute your desire function or script.
To associate custom event to dynamically added node, please refer below code.
<!DOCTYPE html>
<html>
<head>
<title>adding javascript to custom widgets</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
</head>
<body>
<section class="team">
<div class="container">
<div class="row">
<div class="container maxwidth">
<button data-tab="tab1" class="active">AA<span></span></button>
</div>
<div class="maincontent"></div>
</div>
</div>
</section>
<script>
$(function(){
$(".active").click(function(){
$(".maincontent").append("<div class='scroll'><h2>Hello</h2><div style='background:red; height:500px;'></div></div>")
$(".maincontent").find(".scroll").trigger('dynload');
});
$('.container').on('dynload', '.scroll', function(){
console.log("Append event fired");
// Additinal Script resource you want to load for plugin
$.getScript("Custom_Scrollbar.min.js") //script URL with abosolute path
.done(function() {
// Script loaded successfully calling of function
$(".scroll").mCustomScrollbar({
});
})
.fail(function() {
// Give you error when script not loaded in browser
console.log('Script file not loaded');
})
})
})
</script>
</body>
</html>
Hope this will help!
You should init JS as:
<script type="text/javascript">
$( document ).ready(function() {
var some-generated-options = {};
$('#some-generated-id').datetimepicker(some-generated-options);
});
</script>
Like you I did own custom widget that look as:
class DaysInput(TextInput):
def render(self, name, value, attrs=None):
result = super(DaysInput, self).render(name, value, attrs)
return u"""
%s
<script type="text/javascript">
$( document ).ready(function() {
$('a.id_days').click(function(e){
e.preventDefault();
$('input#id_days').val($(e.currentTarget).attr('attr-value'));
});
});
</script>
<a href="#" class="id_days" attr-value='1'>1d</a>
<a href="#" class="id_days" attr-value='2'>2d</a>
<a href="#" class="id_days" attr-value='3'>3d</a>
""" % result
class TestForm(forms.ModelForm):
days = forms.IntegerField(widget=DaysInput())
How can I insert javascript in asp.net MVC application(view)?
I am doing following things in my javascript:
1) Read values from DOM elements.
2) Send data to Controler action method from Jquery Ajax.
3) Validating my input.
4) Read/Write cookies
How can I insert javascript in View.
Should it be something like this?
<script src="../Scripts/Jquery-2.1.js" type="text/javascript"></script>
<script src="../Scripts/jquery.cookie.js" type="text/javascript"></script>
<script>
$(document).ready(function ()
{
$.cookie("pc", "Navada, US");
}
);
</script>
#{
ViewBag.Title = "ViewPage1";
}
<h2>ViewPage1</h2>
Thanks for your answer
Not sure if i understand your question right, but if so you may need to put your script tags into the head tag.
To be able to put your custom js things into head you could try looking at this example:
In your _Layout page add this between <head></head>:
#RenderSection("CustomScripts", required: false);
And on your page:
#section CustomScripts
{
<script src="#Url.Content("~/Scripts/foo.js")" type="text/javascript"></script>
}
EDIT: as #Liam correctly pointed out that the _Layout file could be in any other path, #StephenMuecke's clarification applied.
I want to include lines 4-6 in the Scripts section of the page. The code below is in my view. Instead of being written to it prints to the page. I can't figure out what I'm doing wrong. Somehow it seems this is a very uncommon thing to do as I am not finding examples of how to do it correctly.
1 #section Scripts {
2 #Scripts.Render("~/bundles/jqueryval")
3 #Scripts.Render("~/bundles/datetimepicker")
4 $(function() {
5 $(".datetimepicker").datetimepicker();
6 });
7 }
keep it inside the script tag
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/datetimepicker")
<script type="text/javascript">
$(function() {
$(".datetimepicker").datetimepicker();
});
</script>
You script needs to be in a <script> tag
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/datetimepicker")
<script type="text/javascript">
$(function() {
$(".datetimepicker").datetimepicker();
});
</script>
}
If your view uses the _Layout.cshtml page then you can add a custom section like this at your _Layout.cshtml page:
#RenderSection("scripts", required: false)
If you want all you page should require this section then set require:true
In your view you code should look like this:
#section scripts{
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/datetimepicker")
<script>
$(function() {
$(".datetimepicker").datetimepicker();
});
</script>
}
Just add a script tag and put this code inside the script tag
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/datetimepicker")
<script type="text/javascript">
$(document).ready(function () {
$(function() {
$(".datetimepicker").datetimepicker();
});
});
</script>
}
But There might be a problem because sometimes the asp does not render the scripts . Also you do need to render the scripts in the partial views in case.
I have below view with scripts at the end:
View:
(...)
// here my html items etc...
(...)
<script type="text/javascript" src="~/Scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
// here all my stuff
function sample1()
{
}
function sample2()
{
}
function sample3()
{
}
</script>
so what I want is to put all the code within into a js file and place it under /Scripts folder in mvc 4 so how to do this? In this script I refer to items in the view.
so after this change I have:
View:
(...)
// here my html items etc...
(...)
<script type="text/javascript" src="#Url.Content("~/Scripts/jquery-1.10.2.min.js)"></script>
<script type="text/javascript" src="#Url.Content("~/Scripts/Customs/MyCustomJsFile.js")">
</script>
Javascript file (under /Scripts folder):
MyCustomJsFile.js:
function sample1()
{
}
function sample2()
{
}
function sample3()
{
}
in runtime I am getting an error saying synatx error in MyCustomJsFile.js in the ie debug console so I click the error and first line is shown as error:
but my js file has not any script line....
The only thing that should be in your MyCustomScript.js file is the code you had between the <script> tags, not the tags themselves nor the <script> tag to include jQuery. jQuery should be included in your view on in your Layout and it should be included before your file.
For example, your view:
<script type="text/javascript" src='#Url.Content("~/Scripts/jquery-1.10.2.min.js")'></script>
<script type="text/javascript" src='#Url.Content("~/Scripts/Tests/MyCustomScript.js")'></script>
Your MyCustomScript.js file:
// here all my stuff
jQuery should really be included on your Layout since you will likely be using it on most, if not all, of your Views.
I'm using MVC 3 with the Razor view engine and I would like to inject scripts from multiple views into one centrally defined $(document).ready(); function in the master page.
I have tried the following:
<script type="text/javascript">
$(document).ready(function () {
//OnLoad Script load area
'#RenderSection("DocumentReady", false)'
});
</script>
In my master view, and then:
#section DocumentReady{
alert('Document is ready!');
}
In my view, but unsuprisingly, we get compilation errors due to the javascript not being within a <script> tag.
If there are a lot of small view controls that need to run some initialisation script in the $(document).ready() function, it would be nice to keep them all together in a single place.
Is there a way to inject javascript to a master view without the surrounding <script> tags and without affecting compilation?
You don't need the single quotes around the RenderSection call in your layout:
<script type="text/javascript">
$(document).ready(function () {
#RenderSection("DocumentReady", false)
});
</script>
and inside the view:
#section DocumentReady {
alert('');
}
But it will probably be more readable if you have a scripts section in your layout:
#RenderSection("Scripts", false)
and inside the view:
#section Scripts {
<script type="text/javascript">
$(function() {
alert('');
});
</script>
}
For example, in your _layout.cshtml :
#RenderSection("JavaScript", required: false)
And then in your view :
#section JavaScript
{
<script type="text/javascript" src="#Url.Content("/Scripts/SomeScript.js")"></script>
<script type="text/javascript" src="#Url.Content("/Scripts/AnotherScript.js")"></script>
<script type="text/javascript">console.log("in the js");</script>
}
Hope that helps