Adding - button on Image ( JavaScript ) - javascript

I am building a BlogApp and I am trying to add button on Image. I am showing image from django database in javascript (HTML).
I am trying to add clickable button on Image.
views.py
def user_stories(request):
posts = BlogPost.objects.filter(user=request.user)
template.html
<script>
var blogposts = new BlogPost('blogposts', {
blogposts: [
// {% for post in posts %}
BlogPost.buildTimelineItem(
'{{ post }}',
'{{ user.profile.file.url }}',
'{{ post.user }}',
'{{post.id}}',
timestamp(),
[
[
'{{post.id }}-1',
'photo',
3,
'{{ post.image.url }}',
'',
false,
false,
timestamp(),
],
]
),
// {% endfor %}
],
});
</script>
BlogPostJS.buildTimelineItem = (id, photo, name, link, lastUpdated, items) => {
const timelineItem = {
id,
photo,
name,
link,
lastUpdated,
items: []
};
each(items, (itemIndex, itemArgs) => {
timelineItem.items.push(BlogPostJS.buildBlogPostItem.apply(BlogPostJS, itemArgs));
});
return timelineItem;
};
{{ post.image.url }} is showing image, AND i am trying to add on it.
I also tried by adding :- '{{ post.image.url }}<button type='submit' </button>', BUT it is not showing on image.
I have no idea , how can i add button on image.
Any help would be Appreciated.
Any help would be Appreciated.

your problem is in BlogPost.buildTimelineItem you either need to modify it to include the button, or postprocess the result and add the button manually once the post is rendered. What you tried passes an invalid url because the function accepts image url which I suppose is rendered into an <img> tag.

Related

Add a download functionality in django change view

I already added a button alongside the save buttons for my django change view:
{% extends 'admin/change_form.html' %}
{% load static %}
{% load i18n %}
{% block submit_buttons_bottom %}
<div class="submit-row">
<input type="submit" value="Download" id="download_profile" name="_continue">
<input type="submit" value="{% trans 'Save' %}" class="default" name="_save">
<input type="submit" value="{% trans 'Save and add another' %}" name="_addanother">
<input type="submit" value="{% trans 'Save and continue editing' %}" name="_continue">
<!-- inmport script -->
<script src="{% static '/js/downloadData.js' %}"></script>
<script src="{% static '/js/collapsibleSection.js' %}"></script>
<script src="{% static '/js/investmentAdminScript.js' %}"></script>
{% endblock %}
and I already started adding the script to retrieve individual data per row to download them.
'use strict';
window.addEventListener('load', () => {
const downloadButton = document.querySelector('#download_profile');
downloadButton.addEventListener('click', e => {
if (!confirm('Data will be saved before downloading. Are you sure you want to continue?')) {
e.preventDefault();
return;
}
// get module
const fieldsets = document.querySelectorAll('fieldset');
fieldsets.forEach(thisFieldset => {
const dataRows = thisFieldset.querySelectorAll('.form-row');
dataRows.forEach(dataRow => {
// retrieve each input field and add a download to .xlsx function
});
});
});
});
However, it gets complicated very fast. Is there a better way to do this?
Found a single JS file that allows you to format .xlsx files and start a download with one function
https://github.com/egeriis/zipcelx
Since you're using django, download the "standalone.js" file and add it to your static files. Reference it in your template in a script tag. Now you'll have access to the "zipcelx()" function
Here's a "getting started" example I made
const config = {
filename: "practice-file",
sheet: {
data: [
// Row 1
[
{value: "row1 value1",type:"string"},
{value: "1000",type: 'number'}
],
// Row 2
[
{value: "row2 value1", type: 'string'},
{value: "row2 value2", type: "string"}
]
]
}
}
// call zipcelx to immediately start the download in client's browser
zipcelx(config)
Example of the File Generated
Don't know how large your data sets are, might get tedious with having to format your data in such a way. Some helper functions should do the trick if that became a problem.
Hope this helped!

I am trying to create a like and dislike button for different posts on a page using JavaScript and Django but it seems to work first post only

For the most part, I've managed to create a thumbs up and thumbs down icon working as a like and dislike button, it increases and decreases the count as well for the FIRST POST ONLY, and whenever I click on a like button in any post beside the first post, the button doesn't toggle for that post, it toggles for the first post instead and shows count there. When I refresh the page, the count for other posts gets updated but the button never toggles.
main.js
function likeOnClick(id) {
// $('#likes').click(function () {
var postId;
// postId = $('#likes').attr("data-postId");
postId = id;
console.log("I went inside the function", postId);
var currentClass = $('#likes').attr('class');
if (currentClass == 'fa fa-thumbs-up')
{
$("#likes").removeClass("fa fa-thumbs-up");
$("#likes").addClass("fa fa-thumbs-down");
$.get('like_post/', { post_id: postId, ld: 'l' }, function (data) {
$('#like_count').html(data);
// $('#likes').hide();
});
}
else{
$("#likes").removeClass("fa fa-thumbs-down");
$("#likes").addClass("fa fa-thumbs-up");
$.get('like_post/', { post_id: postId, ld: 'd' }, function (data) {
$('#like_count').html(data);
});
}
// });
};
HTML
{% for d in page_obj %}
<div class="secondSection">
<div class="container">
<div class="card" id = "cardID">
<h4>{{d.created_by}}</h4>
{% if request.user == d.created_by %}
Edit
{% endif %}
<p id="contents">{{d.postContent}}</p>
<small>{{d.dateAndTime}}</small>
<strong id = "like_count">{{ d.likes }}</strong>
{% if user.is_authenticated %}
<i class="fa fa-thumbs-up" id="likes" onclick="likeOnClick('{{d.id}}');"></i>
{% endif %}
</div>
</div>
{% endfor %}
function likeOnClick(ele, id) {
var postId;
postId = id;
console.log("I went inside the function", postId);
var currentClass = $(ele).attr('class');
if (currentClass == 'fa fa-thumbs-up')
{
$(ele).removeClass("fa fa-thumbs-up");
$(ele).addClass("fa fa-thumbs-down");
$.get('like_post/', { post_id: postId, ld: 'l' }, function (data) {
$('#like_count').html(data);
// $('#likes').hide();
});
}
else{
$(ele).removeClass("fa fa-thumbs-down");
$(ele).addClass("fa fa-thumbs-up");
$.get('like_post/', { post_id: postId, ld: 'd' }, function (data) {
$('#like_count').html(data);
});
}
};
Please try this and you need to pass this to onclick event handler.

How to attach a callback on a recursively generated <select> dropdown?

I'm trying to implement chained dependent dropdown combobox selection, so you start with one combobox for main category and once you select main category, another <select> appears to select a subcategory, and so on until the innermost (most specific) category is selected. The code I have currently only works for one subcategory (direct children), how can I make it work for other levels too? So, I need to attach an onChange callback to a newly created <select> somehow.
This is jQuery code in my Django template:
{% extends 'pages/base.html' %}
{% block content %}
<h1>Create a product</h1>
<form method='POST' id='productForm' data-products-url="{% url 'products:ajax_load_categories' %}">
{{ form.as_p }}
</form>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
$("select").change(function () {
var url = $("#productForm").attr("data-products-url");
var categoryId = $(this).val();
$.ajax({
url: url,
data: {
'category': categoryId
},
success: function (data) {
$("#productForm").append(data);
}
});
});
</script>
{% endblock %}
Here is my view:
def load_categories(request):
category_id = request.GET.get('category')
subcategories = Category.objects.get(id=category_id).get_children()
return render(request, 'products/category_dropdown_list_options.html', {'subcategories': subcategories})
products/category_dropdown_list_options.html
<select id="select_{{ subcategories.first.get_level }}">
<option value="">---------</option>
{% for subcategory in subcategories %}
<option value="{{ subcategory.pk }}">{{ subcategory.name }}</option>
{% endfor %}
</select>
Here is my urls.py:
app_name = 'products'
urlpatterns = [
path('create/', product_create_view, name='product-create'),
path('ajax/load-categories/', load_categories, name='ajax_load_categories')
]
Here is my Category model as per request:
from mptt.models import MPTTModel, TreeForeignKey
class Category(MPTTModel):
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
name = models.CharField(max_length=255)
slug = models.SlugField()
class Meta:
unique_together = (('parent', 'slug',))
verbose_name_plural = 'categories'
class MPTTMeta:
order_insertion_by = ['name']
def __str__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super().save(*args, **kwargs)
def get_slug_list(self):
ancestors = self.get_ancestors(include_self=True)
slugs = [ancestor.slug for ancestor in ancestors]
new_slugs = []
for idx, ancestor in enumerate(slugs, 1):
new_slugs.append('/'.join(slugs[:idx]))
return new_slugs
def get_recursive_product_count(self):
return Product.objects.filter(category__in=self.get_descendants(include_self=True)).count()
You'll need to turn your jQuery ajax script into a function, then call it recursively, like this:
<script>
var $r_ = function() {
var url = $("#productForm").attr("data-products-url");
var categoryId = $(this).val();
$.ajax({
url: url,
data: {
'category': categoryId
},
success: function (data) {
if (data != 'leaf_node') {
$("#productForm").append(data);
}
$('select').change($r_);
}
});
} //end of $r_
$('select').change($r_);
</script>
Update
If you take a look at the get_children method of the MPTT model, you'll see that it checks whether or not the instance has any children, and returns None if it doesn't.
Add a None check in your view, then add a different response when you've reached a leaf node:
from django.http import HttpResponse
def load_categories(request):
category_id = request.GET.get('category')
subcategories = Category.objects.get(id=category_id).get_children()
if subcategories:
return render(request, 'products/category_dropdown_list_options.html', {'subcategories': subcategories})
return HttpResponse('leaf_node')
Then add a check for leaf nodes in your ajax call (see above).

How to modify shopify reorder to cart to add custom line item properties

I am trying to add a reorder button to my customer's order history pages to automatically reorder items they've already purchased. This would send them back to the cart with items already prefilled and ready for checkout. Each product item has custom properties attached to it. Everything seems to work fine, except that when I add the items back into the cart, I cannot get the custom line item properties to display.
I'm using the order-to-cart.liquid snippet.
On line 18, it seems the custom properties are being called:
properties: {{ line_item.properties | json }}
I've tried to modify the code to add them:
request.send(JSON.stringify({
'quantity':order.items[0].quantity,
'id':order.items[0].variant_id,
'properties':order.items[0].properties
}));
But this does not work.
Based on the comment below, I tried to loop through the item properties:
request.send(JSON.stringify({
'quantity':order.items[0].quantity,
'id':order.items[0].variant_id,
'properties': {
{% for line_item in order.line_items %}
{% for property in line_item.properties %}
'{{ property.first }}': '{{ property.last }}'{% unless forloop.last %},{% endunless %}
{% endfor %}
{% endfor %}
}
}));
But I get syntax error:
SyntaxError: missing } after property list
note: { opened at line 403, column 26
Which seems to reference the property list of request.send
The outputted example json is:
/* Setup the order object. Extend this as needed. */
var order = {
items:[
{
variant_id: 16320547225634,
product_id: 1782978904098,
properties: [["Arrangement Type",""],["Enclosed Card",""],["Occasion \u0026amp; Comments","Condolescens"],["Delivery Date","Mar 29, 2019"]],
available: true
},
{
variant_id: null,
product_id: 1776316743714,
properties: [["Arrangement Type",""],["Enclosed Card",""],["Occasion \u0026amp; Comments",""],["Delivery Date","Mar 24, 2019"]],
available: null
},
{
variant_id: 16319970017314,
product_id: 1782916808738,
properties: [["Arrangement Type","Seasonal"],["Enclosed Card","Love and best wishes"],["Occasion \u0026amp; Comments","Just Because"],["Delivery Date","Mar 25, 2019"]],
available: true
},
{
variant_id: 16311468687394,
product_id: 1780877819938,
properties: [["Arrangement Type","Large vase with orchids"],["Enclosed Card","Steal the warm chair right after you get up when owners are asleep, cry for no apparent reason sleeps on my head."],["Occasion \u0026amp; Comments","Birthday so make extra special!"],["Delivery Date","Apr 10, 2019"]],
available: true
}
]
};
request.send(JSON.stringify({
'quantity':order.items[0].quantity,
'id':order.items[0].variant_id,
'properties': {
'Arrangement Type': '',
'Enclosed Card': '',
'Occasion & Comments': 'Condolescens',
'Delivery Date': 'Mar 29, 2019'
'Arrangement Type': '',
'Enclosed Card': '',
'Occasion & Comments': '',
'Delivery Date': 'Mar 24, 2019'
'Arrangement Type': 'Seasonal',
'Enclosed Card': 'Love and best wishes',
'Occasion & Comments': 'Just Because',
'Delivery Date': 'Mar 25, 2019'
'Arrangement Type': 'Large vase with orchids',
'Enclosed Card': 'Steal the warm chair right after you get up when owners are asleep, cry for no apparent reason sleeps on my head.',
'Occasion & Comments': 'Birthday so make extra special!',
'Delivery Date': 'Apr 10, 2019'
}
}));
My cart.liquid file calls the custom properties like so:
{% if property_size > 0 %}
{% for p in item.properties %}
{% assign first_character_in_key = p.first | truncate: 1, '' %}
{% unless p.last == blank or first_character_in_key == '_' %}
<div class="label-info">{{ p.first }}:
<strong class="input-info">{{ p.last }}</strong>
</div>
{% endunless %}
{% endfor %}
{% endif %}
But I'm not sure if I need to modify this to accommodate any properties already created.
The custom line item properties need to show up when added back to the cart, otherwise the reorder function won't really be a time saver as it will force customers to go back to each product page to re-add info into the custom fields.
I'm not that versed in liquid so not quite sure what needs to be done to modify the snippet or cart templates. Any help you could provide would be greatly appreciated!
Many thanks,
Mark
The reason 'properties':order.items[0].properties does not work is because it contains an array with the name and value of the line item property.
To set this up we will need to turn the array into and object and then pass that into the request.send function.
A function I found that achieves this can be seen in this post. You can copy and paste this function into the orderItems function.
Once that is added we then create the properties variable, passing in order.items[0].properties as an argument to turn this into an object.
This variable is added along with the 'quantity' and 'id' in request.send.
Here is how the orderItems function will look once everything is added:
/* Simple function add to cart */
var orderItems = function(){
if(!order.items.length){ return }
if(!order.items[0].available){
checkQueue();
}
function objectify(array) {
return array.reduce(function(p, c) {
p[c[0]] = c[1];
return p;
}, {});
}
var properties = objectify(order.items[0].properties);
var request = new XMLHttpRequest();
request.open('post', '/cart/add.js', true);
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
request.onload = function() {
var resp = request.responseText;
if (request.status >= 200 && request.status < 400) {
checkQueue();
} else { /* add your error handling in here */ }
};
request.onerror = function() {
/* add your error handling in here */
};
request.send(JSON.stringify({
'quantity':order.items[0].quantity,
'id':order.items[0].variant_id,
properties
}));
};
Hope that helps!

Passing JSON data from views to html via ajax in Django

I cannot render html template with JSON data passed from views via ajax. I get correct JSON format from views and I can see the correct response in console.log(response), but when I run from the browser this url http://127.0.0.1:8000/our-stores/ I get this result:
[{'fields': {'address': 'Kilpolantie 16',
'city': 'Helsinki',
'country': 'Finland',
'name': 'K-market'},
'model': 'shoppire.supermarket',
'pk': 1},
{'fields': {'address': 'Kontulankari 16',
'city': 'Helsinki',
'country': 'Finland',
'name': 'S-market'},
'model': 'shoppire.supermarket',
'pk': 2}]
But instead of this output I should get rendered ourstores.html file. Please, find the code below:
models.py
class Supermarket(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
country = models.CharField(max_length=50)
def __unicode__(self):
return self.name
urls.py
urlpatterns = [
url(r'^our-stores/$','shoppire.views.ourstores',name='ourstores'),
url(r'^admin/', include(admin.site.urls)),
]
views.py
def ourstores(request):
stores_list = Supermarket.objects.all()
response_data = serializers.serialize('json',stores_list)
return HttpResponse(response_data,content_type="application/json")
ourstores.html
{% extends 'base.html' %}
{% block content %}
<div class='col-sm-12' style='text-align:center'>
<h2>Check out our stores:</h2>
<div id="show_stores" onload="ShowStores()"></div>
<div id="results"></div>
</div>
{% endblock %}
ShowStores.js
$(document).ready(function(){
ShowStores();
});
function ShowStores() {
console.log("show stores is working");
$.ajax({
url : "our-stores",
type : "GET",
dataType : "json",
success: function(response){
$.each(response,function(index){
$('#results').append(response[index].fields.name);
console.log(response[index].fields.name);
});
console.log(response);
console.log("success");
},
error : function(xhr,errmsg,err) {
$('#show_stores').html("<div class='alert-box alert radius' data-alert>Oops! We have encountered an error: "+errmsg+
" <a href='#' class='close'>×</a></div>"); // add the error to the dom
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
};
Thanks a lot!
You do not render the ourstores.html template anywhere in your ourstores view. In order for a template to be displayed, it has to be rendered by the view. In your case, if the request is AJAX, you'd want a JSON to be rendered and if the request is not AJAX, the actual template to be rendered.
Your view could look something like this:
def ourstores(request):
if request.is_ajax():
stores_list = Supermarket.objects.all()
response_data = serializers.serialize('json',stores_list)
return HttpResponse(response_data,content_type="application/json")
return render(request, 'ourstores.html')
If you ask for JSON response, JSON response is what you will get.
If you want to render a template, use the following:
def ourstores(request):
stores_list = Supermarket.objects.all()
response_data = serializers.serialize('json',stores_list)
return render_to_response('our_stores.html',
response_data,
context_instance=RequestContext(request))
Then, inside your template use the passed data as {{response_data}}

Categories