I have a javascript code in rendered html page of custom widget. I want to move the js code to separate js file.
However, it must be dynamic not static media file.
I wrote a custom widget:
class CustomWidget(CustomWidgetBase):
css = {
'all': (
config['custom_css'] +
config['extra_css']
)
}
js = (
config['custom_js'] +
config['extra_js']
)
#property
def media(self):
media = super(CustomWidget, self).media
media.add_css(CustomWidget.css)
media.add_js(CustomWidget.js)
return media
def render(self, name, value, attrs=None):
attrs_for_textarea = attrs.copy()
attrs_for_textarea['hidden'] = 'true'
attrs_for_textarea['id'] += '-textarea'
html = super(CustomWidget, self).render(name, value, attrs_for_textarea)
html += render_to_string(
'app/custom_widget.html',
{
'id': attrs['id'].replace('-', '_'),
'id_src': attrs['id'],
'value': value if value else '',
'settings': json.dumps(self.template_contexts()),
'STATIC_URL': settings.STATIC_URL,
'CSRF_COOKIE_NAME': settings.CSRF_COOKIE_NAME,
}
)
CustomWidget.js += (os.path.join(settings.STATIC_URL, 'app/my.js'),)
return mark_safe(html)
'app/custom_widget.html' has javascript code:
{% load staticfiles %}
<div id='{{ id_src }}'>{{ value|safe }}</div>
<script>
$(function() {
var {{ id }}_textarea = window.document.getElementById('{{ id_src }}-textarea');
... omitted ...
I'd like to move javascript code in 'app/custom_widget.html' into 'app/my.js' because it makes widget code dependent on the order of javascript declarations.
Thus, 'app/my.js' must be dynamically generated with the values passed by Django view. I want to place 'app/my.js' at the bottom of the page.
Thank you.
Two options:
You can put a list of variable declarations in a script tag in your template, making sure they're declared before you import your static javascript. Then your static javascript refers to variable values that it knows were appropriately set by the server.
Put your dynamic values in data attributes in your HTML elements. Then write your static javascript to look up the appropriate server-set data based on what it's manipulating.
What you’re doing in your sample code looks very complex and I’m not sure it needs to be. If I interpret correctly, you are trying to make sure that when you insert a custom widget, a custom javascript behaviour will be applied to it.
I think the second option is more appropriate for that behaviour and that you should probably use jquery to make it as simple to implement as possible.
Firstly, in your custom widget’s html template, give your custom widget a class that lets your javascript know to apply custom behaviours to it.
eg,
<input class=“custom-behaviour-widget” data-id_name=“{{ id }}" data-other_variable_name=“other_variable-value" …>
Then write static javascript that looks like:
<script>
$( document ).ready(function () {
$(‘.custom-behaviour-widget’).each(
value_that_i_want = $(this).data(‘id_name’);
...
);
});
</script>
Related
def scan(request):
scan = Stock.objects.all()
hammer = Stock.objects.filter(Hammer=100)
belthold = Stock.objects.filter(Belthold=100)
context = {'All':scan, 'Belthold':belthold, 'Hammer':hammer
}
return render(request, 'scanner/scan.html', context)
This is my views.py file. I want to add a dropdown list to my html page containing the context dictionary which changes the query filters according.
This is my current html page:
{% for i in Hammer %}
<tr>
<td>{{i.script}}</td>
<td>{{i.open}}</td>
<td>{{i.high}}</td>
<td>{{i.low}}</td>
<td>{{i.close}}</td>
<td>{{i.Volume}}</td>
<td>{{i.Change}}</td>
</tr>
{% endfor %}
The 'Hammer' need to be replaced by whatever selection is made from the dropdown list.
THANKS!!
You cannot dynamically change Hammer in a template for loop. You can use the approach below or change the approach as to how you want everything displayed.
You have to use Javascript for that. You first need to give id's to all the tags you have in the for loop.
<td id="{{i.script}}_myid"> ...
Then with Javascript access the change in the dropdown menu's value and then update the respective td's accordingly:
document.getElementbyId('dropdown').addEventListener('change', function(e) {
// Change td's here: document.getElementbyId(..._myid).innerHTML = "" })
To pass Hammer in your JS you can either do an inline script (which many dont recommend) or a separate JS file added as a script tag below. You can use serializers to pass on the objects from Python to JS.
For now on I have in my template a paragraph like this <p class="...">{{ post.content }}</p> and if this Post's content contains a link or #hashtag it is rendered as a normal text with the rest of the post. How can I customize it? For example change text-color and add tag around it?
As I said in comment, you can use custom tag filter to wrap your content, and use Regular Expression to generate links and hashtags
Create your tags file, and name it as you want:
tag_filter_name.py
If you're not familiar with custom tag filter creation, you can learn more about it in the Official Documentation
from django import template
import re
register = template.Library()
def generate_link(link):
return '<a class="link" href="{}">{}</a>'.format(link, link)
def generate_hashtag_link(tag):
# Free to configuree the URL the way adapted your project
url = "/tags/{}/".format(tag)
return '<a class="hashtag" href="{}">#{}</a>'.format(url, tag)
And then, you create the function what will be used as tag filter
#register.filter
def render_content(obj):
text = re.sub(r"#(\w+)", lambda m: generate_hashtag_link(m.group(1)),obj)
return re.sub(r"(?P<url>https?://[^\s]+)", lambda m: generate_link(m.group(1)),text)
If you want Django to mark it as safe content, you can do the following:
from django.utils.safestring import mark_safe # import function
''' function codes here '''
return mark_safe(re.sub(r"(?Phttps?://[^\s]+)",
lambda m: generate_link(m.group(1)),text))
And finally, to use it in your template, don't forget to load it
{% load tag_filter_name %}
{{ post.content|render_content }}
Best way: custom tag filters here is the docs URL
https://docs.djangoproject.com/en/2.2/ref/templates/builtins/
Good way: If you know JS create a function that handles the formatting on the front end
in HTML:
onload="myfunction("{{post.content}}")"
in JS sort for the string containing the # wrap it in a span or other element and style away. then replace the inner HTML with your new formatted piece. This will save rendering time on the server and also frees you up from having to loop thru the list of posts in the view
Ok way: not preferred but if you hate js and only want to work in python (understandable). You need to loop through the list of posts separate out the items of the post format them the way you like with inline style. then add them to a new object that you will append to the end of a new list of posts that you will then pass thru to context. This is a real pain please don't do this if you can help it at all.
the tag filters are awsome take advantage but if they won't work for your use case I would highly advise using vanilla JS
I have a flask backend sending data to the client. Some JS on the client side then utilizes that data to construct a page that includes one row of data and another area below the row that has a d3 display with clickable nodes.
The nodes have different properties corresponding to different models in the backend and different html templates. Given a type, when clicked, a different html template is presented in the row above.
How do I set the template from the JS? I tried doing something like:
$("#div_id").innerHTML = "{% set obj = " + obj + "%}{% include '" + obj_template_file + "' %}"
That (perhaps of course) didn't work. After taking care of escaping, it just displays that string. I thought of dirty ways of doing this like using hide and show liberally but that doesn't seem wise.
ALthough is not clear what you mean by "sending data to the client".
You can pass the base_template argument from your routes like:
#auth.route('/<path:path>', methods=['GET', 'POST'])
def password_reset_request():
if path ==2:
base_template = "jay.html"
if path ==3:
base_template = "blue.html"
...
return render_template('auth/reset_password.html', base_template=base_template)
and on the template:
{% extends base_template %}
THen from your javascript frontend you just need to GET the URL.
How can I check placeholder content existence and make next trick? :
{% if placeholder 'Head_text' %} <--check here
<div class="in">
...
...
<h2 class="title">{% placeholder 'Head_text' %}</h2>
...
...
</div>
{% endif %}
I want to know, does placeholder have some content before rendering some special HTML-structure for it.
Thanks.
I was looking for a solution for this and I found a few alternatives instead of checking if the placeholder exists. Basically the idea is to use a different plugin instead that adds the extra html. There are a few packages you can install with pip. Now, after trying them I just did it myself and it was much more easier than using the packages.
cmsplugin-text-wrapper: It integrates to the existent django-cms default text plugin keeping the editor but adds a selector on top so you can select a wrapper. The wrapper contains the extra html you would like to add. It also has a nice CSS system to add classes. On the downside, I didn't want to make the editors life more difficult with the extra template selector.
cmsplugin-text-ng: This basically adds a new plugin. When you add the plugin to your placeholder, it display a selector with the available templates (that contains your extra HTML). What I really like is that you can add extra fields that you can use in your customized HTML. For example, you could add a title so the plugin displays an extra textfield for it. On the downside, the templates are store in the database through the admin!. That is an extra hit to the database and I really don't want to sacrifice it for something too simple.
Do your own plugin using the existent Text Model. Four very simple steps:
3.1 Basically add this to your cms_plugins.py:
from cms.plugin_pool import plugin_pool
from cms.plugins.text.models import Text
from cms.plugins.text.cms_plugins import TextPlugin
class WidgetPlugin(TextPlugin):
model = Text
name = _("Widget")
render_template = "widget.html"
def render(self, context, instance, placeholder):
context['instance'] = instance
return context
plugin_pool.register_plugin(WidgetPlugin)
3.2 Create your widget.html template in your templates folder:
<div class="in">
...
...
{{ instance.body|safe }}
...
...
</div>
3.3 Place your placeholder wherever you want:
{% placeholder 'Head_text' %}
3.4 Make the user use the new plugin adding the Head_text configuration plugin in the settings.py:
CMS_PLACEHOLDER_CONF = {
#...
'Head_text': {
'plugins': {'WidgetPlugin'}
},
}
I've had this problem before, and when I researched it (this might have changed since) there is no built in way to do this, so you have to write your own template tag to load the placeholder into a variable.
Here are some discussions on the django-cms mailing list:
https://groups.google.com/forum/?fromgroups=#!topic/django-cms/QeTlmxQnn3E
https://groups.google.com/forum/#!topic/django-cms/2mWvEpTH0ns/discussion
Is there a way to replace the main tag on jquery-tmpl ?
Example:
var data = {Name: 'Pele', Languages: ["Portuguese","English","Spanish"]};
So on a script tag we define the following template
Name: ${Name}
{{each Languages}}
I speak $value
{{/each}}
What I wanted to change is ...
Istead of using {{each}} I'd use something like $$each$$
Instead of ${Name} I'd use something like $#Name$
You may be asking yourself why I wanna do this.
The main reason is when I because on the project we're working on uses Django and when we put code like {{each}} (even on script tag with type set to text/html) Django view engine think it's a server tag and tries to render it like if it were a server side tag.
Update:
What I'm looking for is a way to Set a Delimeter on jQuery-tmpl like the one that is avaiable on Mustache.js
http://mustache.github.com/mustache.5.html (look for Set Delimiter)
Thanks.
Sure, if you want a literal { in your HTML, use templatetag with openblock.
{% templatetag openblock %}
If you want a literal }, use closeblock:
{% templatetag closeblock %}
So if you want {{each}} in your HTML, use:
{% templatetag openblock %}{% templatetag openblock %}each{% templatetag closeblock %}{% templatetag closeblock %}
A different approach would be to define the template in a js file which is not processed by django as a template.
If that is not possible another alternative to Dominic's approach would be to define variables for '{{' and '}}' maybe jqtmpl_open and jqtmpl_close accordingly and use them in template like this:
{{ jqtmpl_open }}each Languages{{ jqtmpl_close }}
This would be more readable in the template.
Changing a delimiter for jquery-tmpl is complicated. By looking at the code it seems that {{ is hard coded within some regular expressions there.
var oldManip = jQuery.fn.domManip, tmplItmAtt = "_tmplitem", htmlExpr = /^[^<]* (<[\w\W]+>)[^>]*$|\{\{\! /,
newTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = [];
The only solution would be to fork the jquery-tmpl for your project and change these hard coded regular expressions to accommodate your needs.
This question has already been asked here jquery template tags conflict with Django template! but I thought I would add from my experience.
In a nutshell, I've added this custom "raw" template tag to my jquery-tmpl/django projects: http://www.holovaty.com/writing/django-two-phased-rendering/