I have a view called contact.html.twig. It has a form with some textfields. I want to use javascript to validate that none of the fields are empty, as well as some other rules. But I do not know where to put the .js with the definitions. I do not know either how to call the .js script using the Twig notation.
This is a generic answer for how to handle javascript... not specifically the validation part. The approach I use is to store individual functionality in separate JS files as plugins in the bundles Resources/public/js directory like so:
(function ($) {
$.fn.userAdmin = function (options) {
var $this = $(this);
$this.on('click', '.delete-item', function (event) {
event.preventDefault();
event.stopPropagation();
// handle deleting an item...
});
}
});
I then include these files in my base template using assetic:
{% javascripts
'#SOTBCoreBundle/Resources/public/js/user.js'
%}
<script src="{{ asset_url }}"></script>
{% endjavascripts %}
In my base template I have a block at the end of <body> for a $(document).ready();
<script>
$(document).ready(function () {
{% block documentReady %}{% endblock documentReady %}
});
</script>
</body>
Then in my page that has the "user admin" functionality I can call the userAdmin function like so:
{% block documentReady %}
{{ parent() }}
$('#user-form').userAdmin();
{% endblock documentReady %}
Isn't basic HTML5 functionality enough for your client side validation? It is provided by the Form component. You could also check:
Assetic
Assetic article
Related
I'm having issues calling functions from twig views in Symfony 4.4. This view is called UserList.html.view and it extends base.html.twig
The beginning of the file is as following :
{% extends 'base.html.twig' %}
{% block body %}
{% block javascripts %}
<script src="{{ asset('build/js/custom.js') }}"></script>
...
I also tried with Encore by adding an entry but it's not working. The only way to access external functions is to call them from the parent view which is not what I want obviously.
The error I get :
Uncaught ReferenceError: coucou is not defined
at HTMLButtonElement.onclick (VM3883 manageAccounts:183)
onclick # VM3883 manageAccounts:183
I read some other posts about this but none of them actually provided a working solution.
Thank you for your help !
Hello there and welcome to SO forums. It is hard to put a finger on your issue based on the provided pieces of code - but the twig block usage might be something that is not implemented / working as you assume. Namely the javascript block inside the implemented body block has no relevancy to the a similarly named block in base template (I assume that there is similarly named block there) because it is placed inside the body block which you are completely overwriting in this UserList.html.twig template.
A basic working twig structure would be something like this:
base.html.twig
<html>
<head>
...
</head>
<body>
...
{% block body %}
...
{% endblock %}
...
{% block javascripts %}
...
{% endblock %}
...
</body>
</html>
UserList.html.twig - please note the parent() call that makes sure that the block contents from the inherited template are included as well (i.e. if you have some generic jquery or some other generic js includes defined there) - without the parent() you will be defining the javascripts block contents completely again in this template.
{% extends 'base.html.twig' %}
{% block body %}
...
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script src="{{ asset('build/js/custom.js') }}"></script>
{% endblock %}
I hope everyone is doing great during this troubles times ! France started containment last week so I had plenty of time finding the solution.
Dumbest thing ever but I didn't know that..
In your js external files, you have to declare your functions like this :
window.myfunction = function myfonction(){}
That's all..
Could that potentialy cause security issues ? I don't know so I'm asking xD
My js code is in the .html django template inside a block, this way:
{% extends 'base.html' %}
... some blocks here ...
{% block javascript %}
<script>
$(document).ready(function () {
...
});
</script>
{% endblock %}
Now I need to use in the js code some context vars passed from the view to the template. I used a option where I declared in an html element a data attr using django template syntax {{ ... }}
<div id="order_id" data-order-id={{order.id}}>
and with jq I got this element and read the data value. This way:
var orderId = $("#order_id").data('order-id')
this works fairly well, but I realized if I have the code in the same .html I can use the django template expressions as part of my js code. This way:
var orderId = {{ order.id }};
var changeStatusUrl = "{% url 'orders:change_status' %}"
This works fairly well too, so my question is if this is a good practice to follow with, or if this has some drawback that I will face in the future.
If the proyect is medium sized. What I normally implement is to have a separate JavaScript file. Before the import of the file I generate the needed variables from Django template expresions.
For instance if drawing a line graph. My variable data would have the needed values. Then I would import a script that buids in top of the variable.
<script>var data = [{% for s in stats %}{{s}},{% endfor %}];</script>
<script src="{% static "myapp/js/line.js" %}"></script>
Simplified, structure of my project in regard to JavaScript usage is as follows:
base.html (project's base template)
{% block js %}{% endblock %}
<script type="application/javascript" src="/base.js"></script>
child.html (a template, that inherits from base.html)
{% block js %}
<script type="application/javascript">
{# context_variable is a JSON string generated by handler #}
specialObj = {{ context_variable|safe }};
</script>
{% endblock %}
base.js (project's main script)
function specialFn() {
// something is done with specialObj here...
}
if (specialObj)
specialFn();
Question is: should I redeclare obj in base.js for readability (or some other reason)?
I assume you mean specialObj? You are defining it as a global variable, so it is already available to base.js. No need to redeclare.
Is there a good, performant and/or recommended way to declare and provide JS dependencies for blocks in Django templates?
Basically what I want to do is this:
In a Django template file containing a block, declare: I need JS library X to function.
In the tag of the page, upon rendering the page, insert a script tag for this library, but never more than once.
The reasons:
Minimize number of unnecessary JS libraries included in the page to keep load time acceptable in old browsers. (some libs like jquery-ui are very heavyweight for old IEs)
Prevent potentially repeated loading of JS libraries, both for performance and bug-prevention reasons. This happens when you have repeated blocks or multiple blocks including the same JS lib.
I've seen some potential solutions to this but none of them were very compelling from a performance or clarity perspective, so far.
You could use the {% include %} template tag. If you load js into the header you could do something like this:
base.html
<head>
<title>XXXX</title>
...
<script type="text/javascript" src="{{ STATIC_URL}}js/jquery.js"></script>
...
{% block site_header %}{% endblock %}
</head>
other.html
{% extends "base.html" %}
{% block site_header %}
...
<script type="text/javascript" src="{{ STATIC_URL }}admin/js/urlify.js"></script>
..
{% endblock %}
You will have to adjust templates/pathes/etc. to your needs.
For this purpose, I personnaly use Django
Sekizai.
In my base template I have this block :
{% load sekizai_tags %}
<body>
# your own logic here
{% with_data "js-data" as javascripts %}
{% for javascript in javascripts %}
<script type="text/javascript"
src="{{ STATIC_URL }}{{ javascript }}" ></script>
{% endfor %}
{% end_with_data %}
</body>
Then, in my included or extending templates :
{% load sekizai_tags %}
{% add_data "js-data" "myapp/js/script.js" %}
Note you can define multiple blocks, and also use it for CSS, which is very
convenient.
Files added with "add_data" tag will never be repeated even if added several
times.
Can I use Django's template tags inside Javascript? Like using {% form.as_p %} in jQuery to dynamically add forms to the page.
Yes, I do it frequently. Your javascript has to be served through django, but if you just have it in the html header as inline javascript you'll be fine.
E.g: I use this to put prefix on a dynamic formset I use.
{% extends "base.html" %}
{% block extrahead %}
<script type="text/javascript">
$(document).ready(function() {
{# Append fields for dynamic formset to work#}
{% for fset, cap, _, tid in study_formsets.fset_cap_tid %}
$(function() {
$('.form_container_{{ tid }}').formset({
prefix: '{{ fset.prefix }}',
formCssClass: '{{ tid }}',
extraClasses: ['myrow1', 'myrow2']
});
});
{% endfor %}
});
</script>
{% endblock %}
Note in "base.html" I have a html head where the jquery libraries are loaded, that contains {% block extrahead %}{% endblock %}.
You can't use Django's template tags from your Javascript code if that's what you mean. All the Django variables and logic stop existing after the template has been rendered and the HttpResponse has been sent to the client. At that moment when Javascript executes, the client (browser) has no notion the variables you rendered the template with (such as "form").
What you can do is have Javascript modify your HTML page using chunks of HTML that were rendered by your Django template.
If you want to generate HTML on client side, I'd recommend to look at client side tempalte libraries (eg. JQuery Templates - use those with the {% verbatim %} templatetag).
If you want to use variables inside your rendered javascript I (that's my opnion), think it's a bad idea. But if all you want is to generate URL for your views, media and static files, I do this a lot.
Take a look to this github: jscssmin
Yes, you can use`
Example : `{{ user.username }}`
Be sure this is not single quotes but '(back tick / back quote)