List.pop() in Django Template without for loop - javascript

I have a list of id all_entries_user. They basically serve as a part of url for rest service that I have developed using TastyPie. Inside my Django template i want to use them by iterating all_entries_user
function ajaxCall(){
$.getJSON("http://localhost:8000/api/Location/" + {{ all_entries_user.pop }} + "/?format=json",
function(json) {
convert(json,"googleMapUser");
}
);
}
Using this I am getting values from Service and this happens in a continous interval .
interval = startInterval(ajaxCall, 3000);
The value of url must change for each call and it must be taken from list
all_entries_user
gives me the same id every time.
I tried to pop values but each time gives me same value
I havent found an efficient way to iterate through this.
Suggestions and Help Please

Why don't you use the for construct?
{% for user in all_entries_user %}
Do your thing with {{ user }}
{% endfor %}

It's very confusing when you mix two languages. What's happening is your javascript is getting "Built" once when the template is rendered so you only have one URL regardless of how many times javascript hits that method. You can verify this by using view source and checking out what your javascript looks like to the client.
If you want the client to call a different URL each time, you will have to send all the IDs down to the client first. One way to do this is by using json serializer or just a simple home grown javascript array builder.
Something like this might work:
<script>
var allEntries = [{% for entry in all_entries_user %}{{ entry.id }},{% endfor %}];
for (entryId in allEntries) {
doSomethingWith(entryId);
}
</script>
This isn't the best way to populate an array of javascript from django, but it works in a hurry.

Related

set twig variable from json array

As twig renders prior to any javascript, I'm running into what feels like a minor problem.
I need to set a variable in twig that I receive from JSON array, but I'm running into some problems, and I feel like this should be simple.
The data is fed to twig through symfony through a json array, and renders different messages depending on one element in the array; this part works without trouble.
I am able to print the output to the twig file; that works fine. The problem is that I'm having a hard time setting this to a twig variable so that I can use it in a few places.
This works fine:
$('.id').html(items[0].id);
and prints out to the twig here correctly:
<div class="id"></div>
I tried to do do something like this:
{% set requestid = '<div class="id"></div>' %}
{{ requestid }}
But as expected this simply rendered the HTML without the value.
I've been attempting to do something like this:
In the twig I have this:
{% set requestid = "request_holder" %}
{{ requestid }}
And in the jquery I have something like this:
var reqid = items[0].id;
reqid.replace("request_holder",reqid);
I also attempted something like this
var request_id = items[0].id;
window.location = request_id.replace("request_holder",request_id)
I feel like I'm missing a small piece.
**Edit for clarity **
The JSON array is being parsed by jquery.
I have the value of items[0].id
Additional edit here - to make it clear that I was confused: cleaning up a little so as not to send future readers down the wrong path
I believe[d] that the variable needs to be assigned in the javascript because the twig, which is php, is generated prior to the javascript.
I have been attempting to generate the twig in the javascript to no avail.
Here's what I have been attempting:
var requestitem = items[0].id;
$('.id').html("{% set requestId = " + requestitem + " %} <br/> {{ requestId }}");
This defines requestId as a string and is only returning + requestitem + onto the page.
When I attempt this (without the quotations)
var requestitem = items[0].id;
$('.id').html("{% set requestId = requestitem %} <br/> {{ requestId }}");
The twig does not recognize requestitem at all
I have attempted quoting out the twig brackets (e.g. "{" + "%" etc) but this of course only prints them onto the page and does not interpret them.
Twig processes on the server side. It takes variables and renders them as HTML and text. What gets displayed in the browser is just HTML / text / and Javascript. So your set requestid = "request_holder" and {{ requestid}} are just turned to text before they get to the browser.
After that, you have HTML and text on the front end which Javascript can interact with. If you need this id to change on the front end, it needs to be done in Javascript.
What are you using the id to do?
Thanks to the hint from ASOlivieri, I was able to realize what I was doing wrong. I'm putting this here in case anyone comes across this. I was simply looking for a way to create a variable and make it reusable (I didn't go into details as that seemed extraneous).
The data was only available in the JSON array, so any attempt to write it to a twig file would fail, quite simply because it had already been converted to HTML, so I was forced to find another solution,
I was able to keep the variable in a javascript as I had it before
var request_item = items[0].id;
As my original goal was to get the value to update the application through php, I simply needed to use this variable in an AJAX call, and pass it through the path I had wanted to use in twig. Here's a brief summary:
$('#mark-received').click(function()
{
var requestURL = "{{ path('my_path') }}";
jQuery.ajax({
url: requestURL,
type: 'GET',
data: {'id' : request_item},
success: function success(data, text, xhr){
$('#mark-received').addClass('hidden');
$('#received-canceled').removeClass('hidden');
$('header > .alerts').append( $('<div>Success Message</div>').addClass('alert alert-success'));
},
error: function error( xhr, status, err){
$('header > .alerts').append( $('<div>There is a problem. <div class="close">x</div></div>', err).addClass('alert alert-danger'));
}
})
});

Should Django forms be populated on client-side when used as popus

My question is best described by example.
Consider a table of students. When I click on a student, a pop-up should be opened with comprehensive info on the student. At first, each time the user clicks on a student, I did a GET-request via Ajax, and populated the pop-up with the fetched response. In other words, I did something like this:
def my_view(request):
if request.method == 'GET':
model_instance = MyModel.objects.get(id = request.POST['id']):
context = {'my_form': MyForm(instance = model_instance)}
msg = render_to_string('my_template.html', context, request = request)
return JsonResponse({'object': msg}, safe = False)
else:
# POST-request for saving input data to db
And then in the JS code:
$.get(....., function(response){
$(response.object).modal('show');
}
The problem with this code is that the pop-up appears with a delay. Well, yes, it's half a second, and yet I would like the response to be instant. Especially, if the user has slow internet, user experience is even worse.
What is the best-practice here ? On alternative that occurs to me is the following: when rendering the main page (with student tables), pass an empty form (or as Django doc calls it, unbound form by doing my_form = MyForm()), and then populate it with JavaScript when the user clicks on a student. Well, this approach yields super-fast pop-up rendering, and yet the approach is not DRY, the case with ForeignKey fields is very nasty here, and in general, this approach seems junk code
Populating the form with JavaScript doesn't have to be ugly. I've done something like this before using HTML data- attributes to help keep things clean. If you're using jQuery, it could look something like this:
{% for student in students %}
<div class="student" data-student-id="{{ student.id }}" data-student-first-name="{{ student.first_name }}">
{{ student.first_name }}
</div>
{% endfor %}
<!-- Pretend this is inside a modal -->
{{ form.as_p }}
<script>
$('.student').click(function() {
var studentId = $(this).data('student-id');
var firstName = $(this).data('student-first-name');
$('#id_id').value = studentId;
$('#id_first_name').value = firstName;
});
</script>
This assumes that Student.id is a HiddenInput Widget.
It doesn't take much JS to get you a pretty good result.

FOR loop over a Django model in a JS script

I just started a web app using Django and HTML/Javascript templates.
My Django spot app contains a Spot model that is sent to a HTML template - to be used with the Google Map Api. I've encountered a problem when looping over the variable spots containing Spot.objects.all().
It seems the problem comes from the way I send the data to the HMTL file.
----------------------------------------- Spot Django-app : models.py --------------------------------------------
class Spot(models.Model):
idn = models.IntegerField(unique = True)
name = models.CharField(max_length = 200)
longitude = models.FloatField()
latitude = models.FloatField()
------------------------------------------------- HTML / JS -----------------------------------------------
<script type="text/javascript">
var IDs = []
var names = []
var lat = []
var lng = []
{ % for spot in spots % }
IDS.push( {{spot.idn}} );
names.push( {{spot.name}} );
lat.push( {{spot.latitude}} );
lng.push( {{spot.longitude}} );
{ % endfor % }
Then, the lists do not contain any data that can be used afterwards. Worse, the HTML file does not work if the names.push( {{spot.name}} ) is un-commented.
----------------------------------------- Spot Django-app : views.py --------------------------------------------
from spots.models import Spot
def index(request):
return render(request, 'index.html', {'spots':Spot.objects.all()})
Thanks to the other stackoverflow questions (listed below), I also tried to serialize the Spot.objects.all() either with django.core.serializers.serialize("json", Spot.objects.all() ) or by creating my own serializer (thanks to Django_REST). The problem remains the same. So is the problem in the way I parse my data with JS?
I've look the following link :
Returning JSON array from a Django view to a template
django for loop in a .html template page (newbie)
Django FOR LOOP in JavaScript
with no success. So if the answer is included or related to these topics, would you mind explaining me something I've been working around for days ...
EDIT:
The problem was plural:
Serializing the data (or not ; I did not for now but everyone who answered agreed to say that it's better to)
Adding the quotes from {{ spot.name }} to '{{ spot.name }}', only to non Integer/Float models (i.e. only the models.CharFields fields)
Google Maps Api may return errors for some (longitude, latitude) tuples even if they are well-defined
Django will not recognize those template tags because you have spaces between the brace and the percent. So, there is no looping being done at all. You need to write them in the correct format:
{% for spot in spots %}
...
{% endfor %}
Once you do that, you'll start getting all sorts of JS syntax errors because you have not wrapped any of your data in quotes. But, as the comments say, doing this as JSON would be much better.
Even that I think that serializing your data into Json is much better idea. Your javascript code does not work because e.g. {{ spot.name }} will render raw string so for javascript to understand it you need to put it in quotes (and of course semicolon after each line).
names.push('{{spot.name}}');

how to pass javascript variable into liquid markup?

I have a value from JavaScript:
var customerID = document.getElementById("CustomerID").value;
Now I want query the firstName, lastName from module data, based on that customerID variable.
{module_data resource="customers" version="v3" fields="id,firstName,lastName,titleType,customerTypeId,ratingTypeId" skip="0" limit="10" order="lastName" collection="selected-data"}
{% for item in selected-data.items %}
{% if item.id == 10393092%}
document.getElementById("CAT_Custom_15").setAttribute("value","{{item.titleType.label}}") ;
document.getElementById("CAT_Custom_14").setAttribute("value","{{item.firstName}}");
document.getElementById("CAT_Custom_4").setAttribute("value","{{item.lastName}}");
{% endif %}
{% endfor %}
How should I write the where condition?
Whne I assign instant value that 10393092 in my code above. It is working fine. but I need assign the variable equal to item.id(like item.id == customerID). Anyone can help? Thank you so much
What you are asking for is not possible. Liquid generates a static page, which is then stored on your web server. When a user navigates to your site, the pre-generated page is sent to them. Then the JavaScript in it may execute. At this point, it is impossible to do anything in Liquid. You should be looking for a pure JavaScript solution.
Unfortunately you cannot do that. Reason is liquid is processed at server side and you will be fetching the content from the browser DOM using
var customerID = document.getElementById("CustomerID").value;
When the page loads, the content from server (for module_data) have already processed and after that the DOM elements will load resulting in no data passed to liquid if else condition.
At the moment there is no way to send javascript data to the server for module_data.

Django: reverse parametrized url in JavaScript

let's say one of my urlpatterns looks like this.
url('^objects/update/(?P<pk>\d+)$', views.UpdateView.as_view(), name = 'update-object'),
I need to redirect user to the update page depending on the selected object (the list of objects is populated using Ajax). So I'd like to pass that named url pattern to the JavaScript, in order to build the actual url on the client side.
Example of what I want to achieve:
pass the name 'update-objects' to the function
get the actual url pattern, replace (?P<pk>..) with {pk}
pass the result to the javascript, resulting in : objects/update/{pk}
any tips?
thanks
to make it more clear: at the moment of rendering, I can't do url reverse because the PK is not known yet. I need to make kind of javascript-urlpattern which will later be converted to the real url (i.e. my JS code will replace {pk} part with the actual pk value)
The actual URL reversing must happen on the server side. There are several ways to do this, and the most elegant of these probably depends on how exactly your script and markup are set up for this. One thing I've done recently is to attach the URL to a logical element using HTML5 data attributes, which are easy to retrieve using jQuery. If you're not using jQuery, I'll leave it up to you to translate to pure JS. You haven't provided any code or specifics for your client-side, so I'm kind of shooting in the dark here, but maybe this will give you the idea:
Django HTML template:
<ul class="object-list">
{% for object in objectList %}
<li data-update-url="{% url update-objects object.pk %}">object.name</li>
{% endfor %}
</ul>
JS:
$('.object-list').on('click', 'li' function () {
var updateUrl = $(this).data('update-url')
...
});
It sounds like you need to make an additional ajax call once the object has actually been selected. Don't try and second guess your url.conf by trying to work out the url on the client side - you'd just be making trouble for yourself later. Wait till you can get a pk, then use django's reverse function to give you your url (doing anything else violates DRY).
How about creating a simple view that returns the url -
from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseBadRequest
def get_url(request):
if request.is_ajax() and request.method == 'POST':
obj_id = request.POST['obj_id']
url = reverse('object-update', kwargs{'pk': obj_id})
return HttpResponse(obj_id)
return HttpResponseBadRequest()
Then write a javascript function that gets the url using an ajax call to your new view and then redirects. You'd call this function as soon as the object's been selected. I would suggest using JQuery to do this, pure javascript will require you to write more code, and probably write browser specific code (depending on your target). Also it supports dealing with django's csrf protection (you'll need to implement this for ajax calls if you haven't already).
var redirect = function(obj) {
$.ajax({
url: '/your-get-url-view/',
method: 'post',
data: {'obj_id': obj},
success: function(url){
window.location = url;
}
});
}
I'm afraid I don't know how you're getting from the selected object to the pk (For simplicity I've assumed it's available to the redirect function) - you may have to do some processing in the view to get there.
I haven't tested the above code, but it should give you an idea of what I'm suggesting.
Try this one:
Reverse method for generating Django urls
https://github.com/mlouro/django-js-utils
One more
https://github.com/Dimitri-Gnidash/django-js-utils
If you have a URL that only has one PK field in it, you could resolve it with any number (e.g. 0), then substitute the number as required.
In my scenario my URL had a pk then an upload_id, so I had to replace on the right most instance of a 0, with <upload_id>, which the JS would replace this string occurance as required:
detele_url_upload_id_0 = reverse(f'{APP_NAME}:api_upload_delete', args=[pk, 0])
prefix, suffix = detele_url_upload_id_0.rsplit('0', 1)
context['generic_delete_url'] = prefix + '<upload_id>' + suffix
Then in the JS:
const deleteUrl = genericDeleteUrl.replace('<upload_id>', uploadId)

Categories