Javascript Template Engine Use with jQuery - javascript

All,
I'm trying to use the jQuery File Upload Demo:
http://blueimp.github.com/jQuery-File-Upload/
My question is that it says in the Documentation that it uses the Javascript Template Engine (https://github.com/blueimp/jQuery-File-Upload/wiki/Template-Engine)
However, I'm not familiar with this process. I'm trying to integrate this into my Wordpress blog to allow file uploads this way. Within the index.html it has the following Template defined:
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-upload fade">
<td class="preview"><span class="fade"></span></td>
<td class="name">{%=file.name%}</td>
<td class="size">{%=o.formatFileSize(file.size)%}</td>
{% if (file.error) { %}
<td class="error" colspan="2"><span class="label label-important">{%=locale.fileupload.error%}</span> {%=locale.fileupload.errors[file.error] || file.error%}</td>
{% } else if (o.files.valid && !i) { %}
<td>
<div class="progress progress-success progress-striped active"><div class="bar" style="width:0%;"></div></div>
</td>
<td class="start">{% if (!o.options.autoUpload) { %}
<button class="btn btn-primary">
<i class="icon-upload icon-white"></i> {%=locale.fileupload.start%}
</button>
{% } %}</td>
{% } else { %}
<td colspan="2"></td>
{% } %}
<td class="cancel">{% if (!i) { %}
<button class="btn btn-warning">
<i class="icon-ban-circle icon-white"></i> {%=locale.fileupload.cancel%}
</button>
{% } %}</td>
</tr>
{% } %}
</script>
I'm using the jQuery Tmpl code (https://github.com/jquery/jquery-tmpl) and when I try and create this in my Wordpress blog I get some errors in my jquery.fileupload-ui.js file on these lines:
_initTemplates: function () {
var options = this.options;
options.templateContainer = document.createElement(
this._files.prop('nodeName')
);
options.uploadTemplate = tmpl(options.uploadTemplateId);
options.downloadTemplate = tmpl(options.downloadTemplateId);
},
Earlier in this file this is defined as this: uploadTemplateId: 'template-upload',
I'm confused why this wouldn't work or even how to use my own javascript template to do this? When I try and copy these files into my Wordpress blog it always fails and the only thing I don't think I copy is the package.JSON and the .gitignore files in the initial download. What significance do these files play? Just trying to understand what this template is and how to use it?
Anything you can point me to in advance is greatly appreciated! Thanks for the help!

.gitignore is a source control file and not relevant to the scripts - see http://help.github.com/ignore-files/ for more info.
package.JSON is a metadata file for jquery plugins for use by the new jquery plugin site and is nothing to do with the functioning of the plugin you are trying to use - see https://github.com/jquery/plugins.jquery.com#readme for more info.
My best guess for the error is a clash of script files between the plugin and what you already have on wordpress.
Could you post the actual error message(s)?

Related

Can I Reorder a LIst Based On User Provided Values Using Only HTMX?

I have HTMX working. The code below is fully functional. The one piece I'd like to incorporate, I can't figure out how to do it. The user is able to provide a number rank...but when they click save, the view returns with the item at the top. Only after they click reload does the list sort itself based on how I defined the attributes with the model.
Here's my HTML...
<h1 class="title62">Tasks</h1>
<button class="button36" hx-get="{% url 'MyTasks:create_task_form' %}" hx-target="#taskforms">Add Task</button>
<div id="taskforms"></div>
<div id="tblData">
{% if tasks %}
{% for task in tasks %}
{% include "partials/task_detail.html" %}
{% endfor %}
</div>
{% endif %}
<div hx-target="this" hx-swap="outerHTML" hx-headers='{"X-CSRFToken":"{{ csrf_token }}"}' class="" >
<form method="POST">
{% csrf_token %}
<div class="table22">
<table class="table23">
<thead>
<tr>
<th class="title67">Number</th>
<th class="title67">Task</th>
</tr>
</thead>
<tbody>
<button class="button35" hx-post=".">
Save
</button>
<button type="button" class="button33">
Delete
</button>
<tr>
<td class="title73">{{ form.number }}</td>
<td class="title73">{{ form.task }}</td>
</tr>
</tbody>
</table>
</div>
</form>
</div>
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
})
</script>
<div hx-target="this" class="">
<div class="table22">
<table class="table23">
<thead>
<tr>
<th class="title67">Number</th>
<th class="title67">Task</th>
</tr>
</thead>
<tbody>
<button class="button35" hx-get="{% url 'MyTasks:update_task' task.id %}" hx-swap="outerHTML">
Update
</button>
<button class="button34" hx-confirm="Are you sure you want to delete?" hx-post="{% url 'MyTasks:delete_task' task.id %}" hx-swap="outerHTML">
Delete
</button>
<tr>
<td class="title70">{{ task.number }}</td>
<td class="title70">{{ task.task }}</td>
</tr>
</tbody>
</table>
</div>
</div>
My Model...
class Task(models.Model):
task = models.TextField(max_length=264,blank=True,null=True,unique=False)
number = models.PositiveIntegerField(default=1)
class Meta:
ordering = ["number"]
def __str__(self):
return self.task
I have begun to explore using Javascript to do HTML sorting to approach my issue that way instead. It just seems to me as capable as HTMX is there should be a way for me to do it leveraging HTMX. Thanks in advance for any thoughts.
I think the easiest way would be just to swap in the entire list on save instead of just the new item - that way you can take advantage of the ordering in the model.
EDIT:
In order to swap a list of the task in instead of the saved task, you will need to modify your view to return a list of the tasks instead of just the task being saved - like this for a CreateView:
class TaskCreateView(CreateView):
model = Task
form_class = TaskForm
template_name = 'task/_create_form.html'
def form_valid(self, form):
self.object = form.save()
tasks = Task.objects.all()
return render(self.request, 'task/_task_list.html', {'tasks': tasks})
You would also need to make partial template that would render all the tasks - something like this:
<div id="tblData">
{% if tasks %}
<ul>
{% for task in tasks %}
<li>{{ task.order }} - {{ task.task }}</li>
{% endfor %}
</ul>
{% endif %}
The HTMX technique you are looking for is the Out of Band Swapping which is basically 1 request with multiple targets. The targets can be anywhere on the page. In your case: when the user creates, changes or deletes a task, the response should also contain the updated list of tasks. It requires only a few modifications. For example a task updating view:
def update_view(request):
tasks_updated = False
tasks = None
if request.method == 'POST':
form = TaskForm(request.POST)
if form.is_valid():
# Update the task in the database
...
task.save()
tasks_updated = True
else:
# Return the form with errors
return render(request, 'task_form.html', {'form': form})
if tasks_updated:
# Fetch new list of tasks
tasks = Task.objects.order_by('number')
return render(request, 'task.html', {'tasks': tasks, 'task': task})
We have the tasks_updated tracking variable that we switch to True if we updated a task in the database, so the task list needs an update on the frontend. Just before we render the template, we check the value of this variable and fetch the tasks if needed.
And the partial template:
<div>
<!-- Render the task's table as usual. -->
</div>
{% if tasks %}
<div id="tblData" hx-swap-oob="true">
{% for task in tasks %}
{% include "partials/task_detail.html" %}
{% endfor %}
</div>
{% endif %}
Here we render the table only we have the tasks variable, so at least one of the task was updated therefore we loaded the tasks as well. The hx-swap-oob="true" tells HTMX to swap the element having tblData id.
Basically that's it. Just include an OOB-Swap task list in each response, where the task list needs an update. If you load the "new task form" you don't need it, but if you add/update/delete a task, you need a fresh OOB-Swap task list in the response (fetched from the database after the task operation has been finished).

my select2 jquery only work for the first form

i want to use select2.min.js to auto-complete the choices (ForeignKey values) , but it only work for my first form , i used django formset for duplicate forms
this is my snippet
<tbody class="tbody tb1 " id="form_set">
{% for item in items.forms %}
<tr class="p-0 col-12">
<td class="">
<div class="col-12 p-0 mt-3 inp">
<input class="col-12 0qarz qarz" type="number" name="" placeholder="qarz">
</div>
</td>
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{item.price | add_class:'col-12 '}}
</div>
</td>
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{item.quantity | add_class:'col-12 '}}
</div>
</td>
<td class="">
<div class="col-12 p-0 mt-3 inp">
{{item.model | add_class:'col-12 0model model' | attr:'id:model'}}
</div>
</td>
</tr>
{% endfor %}
</tbody>
<script type="text/javascript">
$(function(){
$('.tb1 tr:last').formset({
prefix:'{{items.prefix}}',
addText:'add',
deleteText:'remove',
addCssClass:'btn btn-success',
});
})
</script>
<script type="text/javascript">
$(document).ready(function(){
$("#model").select2()
})
</script>
but the select2 only work for my first form then doesnt have any effect on other forms ! and how to set number of forms to add_class it will help to solve maybe?
thanks
First of all I would love to see a little bit more, for example how you actually define your formset. It is not also clear to me what are you trying to do here. Please paste more data.
I would suggest that you think about using django-select2 module that helps a lot with handling select2 stuff in django.
I am also not sure what you mean by "how to set number of forms", maybe you wish to include some incremental counter that can be done with {{ forloop }} inside for/endfor loop?
Please paste more stuff and answer will be better.
The selector you are using to initialize select2 #model is for element ids, which should be unique for each element in the DOM.
In most browsers the effect will be that only the first instance of an element id will be recognized, and the rest ignored as if they don't exist.
In this instance you want to use a class selector: .model. This will ensure select2 is initialized for all elements that have the class "model". So the code to initialize select2 would be:
<script type="text/javascript">
$(document).ready(function(){
$(".model").select2()
})
</script>
You have to reinitialize(like this way: $("#model").select2();) the select2 for other pages when they appear.
You should need separately initialize with different ids.
for example:
<script type="text/javascript">
$(document).ready(function(){
$("#id_1").select2();
$("#id_2").select2();
})
</script>
the way I found is sending the number of forms through context then apply for loop in the template.
views.py
get_context_data()
context.update({
"accessoryNum": len(StoreRequestAccessory.objects.filter(storeRequestId=self.object.pk)),
"oneDimensionalItemNum":len(StoreRequestOneDimensionalItem.objects.filter(storeRequestId=self.object.pk)),
"twoDimensionalItemNum":len(StoreRequestTwoDimensionalItem.objects.filter(storeRequestId=self.object.pk)),
})
template.html
{% block javascripts %}
<script>
{% comment %} get accessoryNum from context {% endcomment %}
var accessoryNum = {{accessoryNum}};
$(document).ready(function(){
for(let i = 0; i <=accessoryNum; i++){
$(`#id_storereq_accessory_form-${i}-accessoryId`).select2({
placeholder: "Select a Item",
allowClear: true
});
}
});
</script>
{% endblock javascripts %}

Dynamically add or remove table rows with jQuery or Angular?

This is the code I have. I'm using Symfony/Twig to pass the variables and translation strings in (if anyone was unsure what the {{, }}, {% trans %} etc was for).
Please see the line where I have the glyphicon glyphicon-camera - what I want is for the user to be able to click this, and a new row appears directly below containing the contents of row.getPhoto() - the icon will only appear if row.getPhoto() is not null, so therefore clicking it will always mean there is content to show.
Likewise, clicking the photo icon again will make the row disappear.
How can I do this? I'm not sure if I should use jQuery or Angular (I am using both in other places in the project, so both are easily available for me). Any comments welcome, thank you.
<table class="table">
<tr>
<th width="10%">{% trans %} header.item {% endtrans %}</th>
<th width="60%">{% trans %} header.action {% endtrans %}</th>
<th width="10%">{% trans %} header.option1 {% endtrans %}</th>
<th width="10%">{% trans %} header.option2 {% endtrans %}</th>
<th width="10%">{% trans %} header.option3 {% endtrans %}</th>
</tr>
{% for row in showRows(allItems) %}
<tr>
<td>
{{ row.getItem() }}
</td>
<td>
{{ row.getAction() }} {% if row.getPhoto() is not null %} <span class="pull-right show-hide-photo glyphicon glyphicon-camera"></span>{% endif %}
</td>
<td>
{% if row.getOption1() %}<span class="glyphicon glyphicon-ok"></span>{% endif %}
</td>
<td>
{% if row.getOption2() %}<span class="glyphicon glyphicon-ok"></span>{% endif %}
</td>
<td>
{% if row.getOption3() %}<span class="glyphicon glyphicon-ok"></span>{% endif %}
</td>
</tr>
{% endfor %}
</table>
Only jQuery I have right now is this, to make the icon appear like a link when hovered over:
// Photo button
$('.show-hide-photo').css('cursor', 'pointer');
You can always pass symphony2 variables on javascript code, so you can have a scirpt with something along the lines of:
<scirpt>
$(.glyphicon).click(function(){
$(.Some-other-class).toggle()
});
</script>
You can have the .Some-other-class div element or td element starting as hidden and with variables in it (like you did in your static html code).
You don't need the css pointer in the js use it in a css class to have it when the page load not when the user click.
And for your click you can do something like this if you photo is a link then :
first use in your twig a <img src="{{row.photo}}" alt="" style="display:none;"/> whenever you want to put the images.
then inside your js in the click photo button
$('.show-hide-photo').on('click', function(){
$(this).closest('tr').find('img').toggle();
});
$(this) is your show-hide-photo button , closest('tr') will look for the tag which contain your button then find('img') will go find the tag inside that (row) in that case you wont need to bother with ids to select right row etc..

Jquery total noob import inquiry relating to where to put files

I downloaded the Jquery Raty plugin: https://github.com/wbotelhos/raty
Then I installed this folder structure into my {{static_url}}js folder and named it Raty.
Then I imported it into my template as follows and put the path as the location of where its images are stored.
<script type="text/javascript" charset="utf-8" src="{{ STATIC_URL }}js/raty/js/jquery.raty.min.js"></script>
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$('.thingrating').each(function(index){
$(this).raty({
readOnly: false,
path: "{{ STATIC_URL }}js/raty/img/",
start: $(this).children("span:first").text(),
click: function(score, evt) {
var vote_url = "rate/" + this.attr('id').substring(2) + "/" + score + "/";
$.ajax({
url: vote_url,
success: function(){
alert('vote successful');
}
});
}
});
});
});
</script>
Is this correct? I'm not seeing that it is working in my template, so want to make sure this process of storing the script and importing it into my template is correct before I continue to decipher what is wrong...
Here's the rest of my template:
{% block body %}
<h2>Things</h2>
<div class="block" id="block-tables">
<div class="content">
<p></p>
<div class="inner">
<table class="table">
<tr>
<th class="first">Name</th>
<th class="last">Rating</th>
</tr>
<tr class="odd">
<td>{{ item.modelname }}</td>
<td><div class="thingrating" id="t_{{ item.id }}"><span style="display:none;">{{ score }}</span></div></td>
</tr>
</table>
<div class="actions-bar wat-cf">
</div>
</div>
</div>
</div>
{% endblock %}
Take a look at this jsfiddle demo. It works fine (well, except that looks like start should be changed to score as I understand that way you want to define initial score). Incorrect path to images will not break it at all. Browser will simply show default icon for not available image if path to images is wrong. Not sure what is in {{static_url}} variable. If it contains something like 'http://example.com/static' - you must add a slash after it.
Possible problems - script tag for raty appears before jQuery. Or results of template processing are not available on page when $(document).ready event happens.

Rails and ajax file upload - cannot read property 'innerHTML' of null error

I am developing a Rails app with a module for dynamic - ajax - image upload to gallery. I am doing it basing on this app - multi-file-upload-demo. I am not very keen in Javascript and stuff, so I copy a lot of logic from that implementation.
I made up my app following all logic from rounders demo, I have included all gems and javascript libraries, and I get an error:
Uncaught TypeError: Cannot read property 'innerHTML' of null
in chrome console, which refers to tmpl.js file
tmpl.load = function (id) {
return document.getElementById(id).innerHTML;
};
My knowledge of JS doesn't make it clear to me which piece of code triggers that function so I can go further.
Can you advise me what are the next steps to investigate source of this problem? I expect potential reasons may be various, so I don't want to paste all code from the application.
This is old but I found an actual solution to this. Change your require in application.js to //=require jquery-fileupload/basic instead of //= require jquery-fileupload.
The reason you're getting this error is because you are missing a script tag id="template-upload" or id="template-download" or both.
Example from the Demo at: http://blueimp.github.com/jQuery-File-Upload/
<script id="template-upload" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-upload fade">
<td class="preview"><span class="fade"></span></td>
<td class="name"><span>{%=file.name%}</span></td>
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
{% if (file.error) { %}
<td class="error" colspan="2"><span class="label label-important">Error</span> {%=file.error%}</td>
{% } else if (o.files.valid && !i) { %}
<td>
<div class="progress progress-success progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><div class="bar" style="width:0%;"></div></div>
</td>
<td class="start">{% if (!o.options.autoUpload) { %}
<button class="btn btn-primary">
<i class="icon-upload icon-white"></i>
<span>Start</span>
</button>
{% } %}</td>
{% } else { %}
<td colspan="2"></td>
{% } %}
<td class="cancel">{% if (!i) { %}
<button class="btn btn-warning">
<i class="icon-ban-circle icon-white"></i>
<span>Cancel</span>
</button>
{% } %}</td>
</tr>
{% } %}
</script>
<!-- The template to display files available for download -->
<script id="template-download" type="text/x-tmpl">
{% for (var i=0, file; file=o.files[i]; i++) { %}
<tr class="template-download fade">
{% if (file.error) { %}
<td></td>
<td class="name"><span>{%=file.name%}</span></td>
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
<td class="error" colspan="2"><span class="label label-important">Error</span> {%=file.error%}</td>
{% } else { %}
<td class="preview">{% if (file.thumbnail_url) { %}
<img src="{%=file.thumbnail_url%}">
{% } %}</td>
<td class="name">
{%=file.name%}
</td>
<td class="size"><span>{%=o.formatFileSize(file.size)%}</span></td>
<td colspan="2"></td>
{% } %}
<td class="delete">
<button class="btn btn-danger" data-type="{%=file.delete_type%}" data-url="{%=file.delete_url%}"{% if (file.delete_with_credentials) { %} data-xhr-fields='{"withCredentials":true}'{% } %}>
<i class="icon-trash icon-white"></i>
<span>Delete</span>
</button>
<input type="checkbox" name="delete" value="1">
</td>
</tr>
{% } %}
</script>
The UI version depends on both these templates being present.
I was having the same problem and decided to checkout what was missing.
Hope that helps.
I ran into this same problem as well. However, loading the basic version of the file-upload plugin was not an option for me since I use previewing for one upload, but not for the other. You can disable the "preview" functionality and the attempted processing of template-upload and template-download on a case-by-case basis by setting the uploadTemplateId and downloadTemplateId options for the file-upload plugin to null.
The error message tells us that document.getElementById(id) is returning null, so there is no element currently in the document with the specified id.
To debug, try adding a call to console.log(id); before the return statement. Once you do that you can find the value of id that is causing the problem. Hopefully the error is the result of a simple typo, remember the value of id is case-sensitive. If a typo is not the problem, you can at least set a conditional breakpoint since you now know the value of id that you want to break on. After hitting the breakpoint, it's just a matter of stepping through to the calling functions to "see which piece of code triggers that function." Hope this helps.
I'm using this plugin for a few month, today i noticed that file upload didn't work, and i get an error
"cannot read property 'innerHTML' of null error".
I looked into it, and its because a simple reason.
the file path
http://blueimp.github.io/JavaScript-Load-Image/js/load-image.min.js
changed to
http://blueimp.github.io/JavaScript-Load-Image/js/load-image.all.min.js
in the git of blueimp.
as you could see here
https://github.com/blueimp/jQuery-File-Upload
the path changed in this file.
https://github.com/blueimp/jQuery-File-Upload/blob/master/index.html
I changed to the right path and its works.
hope this answer will help someone here that got same problem.

Categories

Resources