With this HTML (twig) :
<li class="ipsFieldRow">
<ul id="customSortable">
{% for plugin in plugins %}
<li id="{{plugin.name ~ '-sort'}}">{{plugin.name}}</li>
{% endfor %}
</ul>
<script>
//Put Here Works Fine
$("#customSortable").sortable();
$("#customSortable").disableSelection();
//Put in a document ready causes the '$(...).sortable is not a function' error.
$(document).ready(function() {
$("#customSortable").sortable();
$("#customSortable").disableSelection();
});
</script>
<li
The problem is described through the two comments in the code. Simply put, .sortable works perfectly when simply inlined into the HTML yet in any jquery callback, it results in the sortable is not a function error. The main reason why this is an issue for me is I want to call sortable('toArray') in a button click callback for server interaction.
As seen through the image, the common issue of the includes being in the wrong order is not the issue here.
You should wrap your code in an IIFE to give yourself an isolated scope.
You can then save a local reference to your jQuery instance, so you'll be unaffected by future changes to the global window.$.
If you installed jQuery yourself (as opposed to relying on an existing copy), you may also want to call .noConflict().
Related
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 %}
When I read the documentation for BindingContext on KnockoutJS website, it has an code example like below to illustrate $data:
<ul data-bind="foreach: ['cats', 'dogs', 'fish']">
<li>The value is <span data-bind="text: $data"></span></li>
</ul>
I am pretty new to KnockoutJS, I wonder is putting a direct array after foreach binding a valid usage? And also in above case, it seems you can omit using applyBinding() to activate. So I guess such syntax is only for illustration purpose, it is not a valid code like what could be in a real KnockoutJS application.
If someone has had similar thoughts and is assured, could you either confirm or correct me?
To answer your first question
'I wonder is putting a direct array after foreach binding a valid usage? '
Yes it is just for illustration purpose they have put the code there. And if you put the code in sinppet code will not work because
They do not want to illustrate foreach here in fact they are giving example of $data.
For foreach documentation take alook here
To another your another question
'it seems you can omit using applyBinding() to activate'
No you cannot omit the applyBinding.
Look in following sinnpet code will not give you desired output unless add ko.applybinding in your code.
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<ul data-bind="foreach: [ 'Jan', 'Feb', 'Mar', 'etc' ]">
<li>
The current item is: <b data-bind="text: $data"></b>
</li>
</ul>
<script type="text/javascript">
//ko.applyBindings();
</script>
As quoted in Knockout documentation
Activating Knockout
The data-bind attribute isn’t native to HTML, though it is perfectly
OK (it’s strictly compliant in HTML 5, and causes no problems with
HTML 4 even though a validator will point out that it’s an
unrecognized attribute). But since the browser doesn’t know what it
means, you need to activate Knockout to make it take effect.
To activate Knockout, add the following line to a <script> block:
ko.applyBindings(myViewModel);
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.
I have to invoke require module in html tag line.Also it is deprecate.I think it is need when html tag dynamic generated.
The require module:
define('index',['jquery','common','stat'],function($,common,stat){
return{
rankList:function(name){
stat.ranklist(name,function(data){
console.log('invoked...');
});
}
}
});
The html tag lines:
<ul class="nav nav-tabs" id="myTab">
<li class="active"><em><strong>任务量大咖</strong></em></li>
<li><em><strong>收入大咖</strong></em></li>
<li><em><strong>准确大咖</strong></em></li>
</ul>
Load script in html:
<script type='text/javascript' src="http://cdn.staticfile.org/require-jquery/0.25.0/require-jquery.js"></script>
<script type='text/javascript' src="../../static/js/app.min.js"></script>
The javascript I tried in html :
<script type="text/javascript">
var rankListCall=(function(){
var index=require(['index']);
return{
rank:function(name){
index.rankList(name);
}
}
})();
I got the script error in line
index.rankList(name);
Uncaught TypeError: undefined is not a function
Most require modules won't export their objects to the global namespace (jQuery is a notorious exception to this, but let's pretend it's not). Therefore, you should try to handle your functions and behaviors inside of the require call. No matter how much you export and include stuff, the DOM won't be able to "see" your functions unless you export them as (for example) window.rankList, but that's like defeating require's purpose.
This is what I'd do to have access both to the dom and the stat function.
define(['jquery','common','stat'],function(jQuery,common,stat){
jQuery(document).on('click','.rankListCall',function() {
var name=jQuery(this).data('name');
stat.ranklist(name,function(data){
console.log('invoked...',name,data);
});
});
});
and yout html code
<ul class="nav nav-tabs" id="myTab">
<li class="active"><em><strong>任务量大咖</strong></em></li>
<li><em><strong>收入大咖</strong></em></li>
<li><em><strong>准确大咖</strong></em></li>
</ul>
instead of trying to export your functions to the global namespace, try to keep the logic separate from the DOM. That way you can handle both functions and behaviors inside the require section. In this case I added a class and a data attribute to your elements to allow jQuery to delegate events on them.
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.