Symfony2 is refreshing a twigs block with ajax possible? - javascript

Lets say I have a block in my layout:
{% block sidebar %} {% render url( 'sidebar' ) %} {% endblock %}
Is it possible to refresh the block with ajax without making a div around it? In my example I cant make a div, because it crashes my whole template so I need to know is that even possible?
For example I can refresh a div like this(.test is the class of the table):
$('.test').load(" .test");
Can I make something like this to refresh the block?
$('sidebar').load(" sidebar");
Any ideas?

Symfony works server side so it can't know what happens in your DOM once the page has been rendered. Also jquery can't know about twig blocks since those are parsed server side.
I'm gona give you a "stupid" (and probably i'm even going against good practices, depending on the content you are rendering) answer but maybe it can be of help: have you tried putting a "span" around it instead of a div?
{% block sidebar %} <span class="test">{% render url( 'sidebar' ) %}</span> {% endblock %}
EDIT:
I think an explanation is due:
This answer is correct assuming there aren't divs inside your sidebar, otherwise it's just a "cheap trick" and might cause other issues (if not now, maybe in the future) See div inside the span element for example.
Probably you should need to check your layout if adding div screws it up.
An alternative i suggest you to try if it can work in your case is to use inline-block divs.
{% block sidebar %} <div class="test">{% render url( 'sidebar' ) %}</div>{% endblock %}
Then, in your css:
.test {
display: inline-block;
}
See http://learnlayout.com/inline-block.html (and remember it's not entirely supported by IE6 and 7)

No. It is not possible.
The reason behind this is separations of web tiers i.e. jQuery runs on Client end which TWIG on Server.

Related

Django and HTMX I am looking for not "hacky" way to update class of link that calls HTMX request. Like "refresh-self" or something along those lines

I have a problem with HTMX in Django. I basically have two important components on page. List of categories and content that is being shown after you click on category.
I was working nicely with just standard htmx "out of the box". But I started having problems when I wanted to add active css class on category link after you click it (to show user where he is currently).
I did a lot of experiments with hx-swap-oob and hx-swap but the only thing that work was this:
(it is the most relevant part of the code)
<div class="col-sm-4">
<div class="card">
<div class="card-body" hx-boost="true" hx-target="#manual_results">
<div id="manual_categories">
{% include 'partials/manual_categories.html' %}
</div>
</div>
</div>
</div>
<div class="col-sm-8">
<div id="manual_results">
{% include 'partials/manual_entries_list.html' %}
</div>
</div>
and in manual_entries_list.html:
<some html results>
<div id="manual_categories" hx-swap-oob="true">
{% include 'partials/manual_categories.html' %}
</div>
Each category has simple if statement in django template code that is checking if it is selected (based on url path.)
And it is working, thing is, on the first request the categories are rendered twice (which is logical since I have 2 includes on the same HTML). After I select one category, everything goes back to normal because HTMX "starts to understand what is happening" and it switches the categories from manual_entries_list.html into our main page.
And like I said it works, I modified manual_entries_list.html to:
<some html results>
<div class="set_size_to_0px">
<div id="manual_categories" hx-swap-oob="true">
{% include 'partials/manual_categories.html' %}
</div>
</div>
So it is always invisible (so I will have only one set of categories visible).
The thing is, that it is an obvious hack. I am sure that there needs to be a better way of solving this problem but I cannot find it.
(I even tried to do it with plain javascript the thing is that categories are rendered in a for loop so it is pretty much impossible to get IDs correctly etc.)
Could someone please help me?
The easiest way to avoid this issue is to detect the HTMX request in the view function, pass this state to your templates and render HTMX content only if needed. HTMX will add a HX-Request: true header to each request.
For the detection you can use the Django-HTMX package that provides a request.htmx variable in your view functions that will be True if the request is coming from HTMX. Or if you want to check it manually:
def my_view(request):
is_htmx = request.headers.get('HX-Request') == 'true'
return render(request, 'my_template.html', {'is_htmx': is_htmx})
After that in manual_entries_list.html template include HTMX related stuff only in the HTMX requests:
<some html results>
{% if is_htmx %}
<div id="manual_categories" hx-swap-oob="true">
{% include 'partials/manual_categories.html' %}
</div>
{% endif %}

Flask - Component templates structure?

I've been experimenting with a Flask template structure to resemble a component workflow. This is inspired by Vue.
Some key ideas :
Each page is treated as a component
A component is just a folder containing all necessary files inside it (except ones that are common)
Each component is encourageg to have several HTML files to avoid large files, we will be using Jinja's include to "bundle" them
togheter
Avoid javascript, or at least, loading unnecessary javascript, each page will include only what's necessary
Here's an example :
The route for PageExample would be the following :
app.route('/example'):
return render_template('PageExample/html.html')
And PageExample/html.html :
{% extends 'base.html' %}
{% block content %}
<div class="tab" id="tab1">
{% include 'PageExample/tab1.html' %}
</div>
<div class="tab" id="tab2">
{% include 'PageExample/tab2.html' %}
</div>
{% endblock %}
PageExample/tab1.html (tab2 follows the same logic)
<!-- block header is in base.html -->
{% block header %}
{{ super() }}
<script src="{{url_for('components', 'PageExample/tab1.js')}}">
{% endblock %}
<div class="tab-content">
Some content here that uses the tab1.js javascript
</div>
So, what's the question ?
I have limited experience with Flask, so I'm not sure if this idea is sound, it seems hacky but it makes developing pages easier, especially with multiple people (the little javascript a page might need can be done in any way). Also increased loading speed by a ton.
Dos this work? Is this structure reccomended? Are there any flaws to it? What sort of problems could I run into? Any recommendation to do it better? Is this already done nowadays in Flask? I couldn't find any examples of a Flask app done this way (specially the Jinja stuff using lots of includes)
I'm currently not at my main computer, so I'll update this later if need be, but if your included html files referenced any data that is stored in the backend then you'd also need to make sure you reference the exact location there as well.
For example:
If you need the first name property from a User class it would be
{{ User.firstName }}
Not only that, but the tab template will also need to be supplied this User.firstName variable, which isn't done implicitly.
You will need to create what is called a Blueprint then a View and tell the view to make the User.firstName variable available to PageExample/tab1.html
tabs.py
import User
from flask import Blueprint, render_template
import """other flask dependencies needed"""
bp = Blueprint('index', __name__, url_prefix='/')
def tabData():
"""data to process"""
render_template("PageExample/tab1.html", User=User)
In that same tabs.py file, you can also write a view for tab2.html as well as html.html. Should be noted that I'm assuming that the contents of PageExample are for the index of the website and that they will all be rendered on that same page.
Also, It seems like your tabs will be in the content/body of the html but it will also render the blocks of base.html and add the defined scripts inline with the body of html.html. Instead, it should be referenced in the html.html file itself
html.html
{% extends 'base.html' %}
{% block header %}
{{ super() }}
<script src="{{url_for('components', 'PageExample/tab1.js')}}">
{% endblock %}
{% block content %}
<div class="tab" id="tab1">
{% include 'PageExample/tab1.html' %}
</div>
<div class="tab" id="tab2">
{% include 'PageExample/tab2.html' %}
</div>
{% endblock %}
with tab1.html being
<div class="tab-content">
Some content here that uses the tab1.js javascript
</div>
Obviously, this is just the surface of what you will need to know about flask. Think the bottom line is that it can work. Although I would suggest that your put all resources such as JS and CSS in a separate folder and reference those resources from those locations.
For more information on Flask and how you can utilise it, check out the Flask Tutorial here:
http://flask.pocoo.org/docs/1.0/tutorial/

Appended content disappears after the change of URL

On my webpage I am using Flask microframework. To give you better understanding of my problem I have decided to include several of my files. Hopefully I won't discourage you.
Example bare in mind this example is incomplete due to complexity of my website. But I hope it will ilustrate the problem.
My script.py which runs the server:
from flask import Flask, request, render_template
app = Flask(__name__)
#app.route('/')
#app.route('/<name>')
def home(name=''):
return render_template('home.html', name=name)
#app.route('/user/')
#app.route('/user/<task>')
def user(task=''):
return render_template('user.html', task=task)
Then I have template.html:
<!-- some html code -->
<div id="navBar"></div>
<div id="mainContent">
{% block content %}
{% endblock %}
</div>
<!-- some html code -->
and user.html:
{% extends 'template.html' %}
{% block content %}
{% if task == 'homework' %}
{% include '/tasks/homework.html' %}
{% endif %}
{% endblock %}
And finally my script.js:
// some jQuery script
$('#button').click(function(){
$('#navTask').empty();
$('#navTask').append('\
<div class="task">\
Homework\
</div>');
});
// some jQuery script
Back to my problem! Basically it does this. Once you click the #button it appends #navTask (which is div located somewhere on the page) with some div with link to /user/homework. Once you click on Homework Flask recognises the change of URL and renders user.html so some part of the webpage changes. My problem is: once you click the link Homework the link Homework disappears too. I am not sure, how to fix it.
I thought, that by appending the div.task to #navBar it will changes throughout the webpage no matter the URL. But as far as I can tell it does not.
I am hoping for this behaviour - somewhere on the page there is a div, after clicking #button, the content changes and new link appears. When you click the link the content somewhere on the page changes, but the link stays where it was. The link might disappear e.g. only when you are on home page.
Note I am now quite sure, if my expectations are real. I could probably do this with just using jQuery, but because the main.py is much more complicated and I am using the data obtained from URL I still go this "way".
Maybe I misunderstood you, but you need to use AJAX request triggered from click on the link if you don't want to refresh all page content.
Whenever was committed not Ajax request to server - the page will be completely redrawn.
On the server side you could check whether it XMLHTTPRequest and if it is return JSON data or other convenient for you.
Maybe this little flask-jquery-example will help you.
P.S. Current location on JS side you can get by window.location.pathname or $(location).attr('href')

Magic-line nav causing some troubles #works only on hrefs included in menu

Im using multiple (2) jquery versions on a site, i thought that it was a problem, but it doesnt seem so. I found out that i actually got a problem with magic-line navigation http://css-tricks.com/jquery-magicline-navigation/ .
What happens is that it works only on sites that are included in the menu itself. Lets say im on projects site(that is included in the menu itself), everything works ok, but when i open a view of a certain project, the "underline" effect stops working, this is how it looks:
i didnt sleep for 4 days, im late for deadline , my brain hurts, plx help
EDIT: i dont think its my code but if it was here it is
some additional info about the code:
base.html
<ul class="group" id="example-one">
{% for i in mains %}
<li class="{% block activetab %}{% endblock %}">{{ i.name }}</li>
{% endfor %}
</ul>
whats included in certain views:
{% block activetab %}
{% ifequal request.get_full_path|cut:"/" i.menulink|cut:"/" %}current_page_item{% endifequal %}
{% endblock %}
It seems that menu buggs if there is no single li with current_page_item class, i hacked it by forcing:
{% ifequal ourprojects i.menulink|cut:"/" %}current_page_item{% endifequal %}
on single project view.
ALthough it works now, it wont if someone changes the path to ourprojects in the admin panel. I would still like to find a proper solution that would work even if someone changes the path... #or i could just disallow changing the path... but thats another sucky solution.
and so it stayed.

Append Django template tag with Jquery

I want to build a menu where I can set one link highlighted using the {% block %} tag. I have something like this in my Javascript:
<loop>
$('#a-div').append('{% block ' + variable + ' %} <a href...</a> {% endblock %}')
<endloop>
In the source, this is displayed as "{% block Home %}"
How can I make JQuery not append this as a string but as a template tag?
You can't. At least not without making an AJAX request to a Django template. In your case, it would be slow and make unnecessary extra requests. It's just not worth it. You can insert snippets from Django templates via jQuery by using, for example, the jQuery load function. But you can't replace a specific {% block %} tag, because by the time jQuery runs, the template has already been processed (and references to block tags removed). But this is not a situation where you should be doing that in any case.
Why don't you rather highlight the menu with a CSS class? Here is my usual solution to this problem:
Create a file called base_extras.py in one of your templatetags folders. If you don't have one, create one in an appropriate folder.
Inside base_extras.py, paste this code:
from django import template
from django.core.urlresolvers import reverse
register = template.Library()
#register.simple_tag
def navactive(request, urls):
if request.path in ( reverse(url) for url in urls.split() ):
return "active"
return ""
Now, in your template, on your menus in your base template, do something like this:
<ul class="menu">
<li class="home {% navactive request 'home' %}">Home</li>
<li class="contact {% navactive request 'contact' %}">Contact</li>
<li class="signup {% navactive request 'signup' %}">Sign up</li>
</ul>
This will make that the menu where your URL currently is has the active class. Then, in your CSS, just add a special class for a menu item with active to look slightly different than the other menus.
ul.menu li.active {background: red; color: white;}
And if you happen to need to change the active menu with jQuery, you can just remove the active class on all menus, and add it to the newly selected menus:
$('ul.menu li').removeClass('active').find('.home').addClass('active'); // for example
You can't do that like that. The Django template tags are processed on the server side, before the page is even sent to the browser. Javascript (including jQuery) is, on the other hand, invoked in the browser, after the page has been received from the server.
What you can do is prerender the content of {% block %} tag to JS variable and use it in jQuery code:
var blockContent = "{% block Home %} ... {% endblock %}";
// ...
$("#a-div").append(blockContent);
If you need more than one block to choose from (as you seem to indicate in the code sample you've provided), you could resort to an array of prerendered blocks.
Your best bet is to create a proxy view that makes what is currently your AJAX request, processes the results like the javascript would, and then returns whatever you're trying to get from the Django templating system.
Then, instead of making the AJAX call you're currently making, you call your own view instead. Django does the processing in the view like it should, you get fine-grained control over what's returned to your javascript, and it's still only one (client-side) server call.

Categories

Resources