在用ajax帮助查询产品后尝试打开带有产品详细信息的模态时出现错误
错误本身:
Uncaught SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at HTMLButtonElement.<anonymous> (scripts.js:54)
at HTMLDocument.dispatch (jquery-3.3.1.js:5183)
at HTMLDocument.elemData.handle (jquery-3.3.1.js:4991)
要清楚:我有一些过滤器,其结果在python filter_items
函数中进行了过滤,然后使用JSONResponse将其发送到前端
以字典的形式(Item模型中的as_dict()
函数)被添加到hidden input
值中。 JS函数采用该隐藏的输入值,并使用来自该输入的数据来呈现过滤结果。
借助过滤器功能查询的项目模型:
class Item(models.Model):
ITEM_TYPES = (
('UM', 'Umbrella'),
('SK', 'Skirt'),
('TR', 'Trousers'),
('OT', 'Other')
)
BRANDS = (
('VS', 'Versace'),
('SP', 'Supreme'),
('SI', 'Stone Island'),
('FP', 'Fred Perry'),
)
title = models.CharField(max_length=256)
image = models.ImageField(upload_to='img/')
brand = models.CharField(max_length=256)
type = models.CharField(choices=ITEM_TYPES, max_length=2)
description = models.TextField(blank=True, null=True)
season = models.TextField(blank=True, null=True)
discount = models.FloatField(blank=True, null=True)
price = models.FloatField()
def __str__(self):
return self.title + ' ' + self.type
def as_dict(self):
data = {"title": self.title, "image": self.image.url, "brand": self.brand, "type": self.type,
"discount": self.discount, "price": self.price, "rus_representation": self.rus_representation,
"description": self.description, "season": self.season, "images": [self.image.url]}
if self.images:
for image in self.images.all():
data['images'].append(image.image.url)
# data['dumped'] = json.dumps(data)
# print(data['dumped'])
return data
def dumped_as_dict(self):
return json.dumps(self.as_dict())
@property
def rus_representation(self):
if self.type == 'UM':
return 'Зонтик'
elif self.type == 'SK':
return 'Юбка'
elif self.type == 'TR':
return 'Штаны'
elif self.type == 'OT':
return 'Другое'
基于类的视图,其中具有过滤器功能:
class ProductsListView(ListView):
model = Item
types = Item.ITEM_TYPES
brands = Item.BRANDS
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['types'] = self.types
context['brands'] = self.brands
return context
@classmethod
def filter_items(cls, request, *args, **kwargs):
if request.is_ajax():
data = request.GET
queryset = Item.objects.all()
if not data['type'] == 'ALL':
queryset = queryset.filter(type=data['type'])
if not data['brand'] == 'ALL':
queryset = queryset.filter(brand__contains=data['brand'])
return JsonResponse({'result': [item.as_dict() for item in queryset]})
JavaScript过滤器功能:
$('.choice-link').click(function () {
var choice = $(this).text();
$(this).siblings().attr('id', '');
$(this).attr('id', 'active');
$(this).parent().parent().children('button').text(choice);
var data = {
'brand': $('.brand-dropdown').children('#active').attr('data-choice'),
'type': $('.type-dropdown').children('#active').attr('data-choice')
};
$.ajax({
url: '../ajax/filter/',
data: data,
success: function (data) {
$('.item-block').remove();
$.each(data.result, function (index, item) {
if (!item.discount) {
var el = '<div class="item-block flex" style="flex-direction: column"><input type="hidden" value='+ JSON.stringify(item) +'><img class="img-fluid" style="box-shadow: 0 0 10px rgba(0,0,0,0.5);" src="' + item.image + '"><h6 class="item-title">' + item.rus_representation + ' "' + item.brand + '"<hr></h6><p class="flex" style="align-items: flex-start"><span class="price-tag">' + item.price + ' $</span></p><button type="button" class="item-btn btn-sm btn btn-outline-info" data-toggle="modal" data-target=".details-modal">Подробней <img style="height: 10px" "></button></div>';
} else {
var el = '<div class="item-block flex" style="flex-direction: column"><input type="hidden" value='+ JSON.stringify(item) +'><img class="img-fluid" style="box-shadow: 0 0 10px rgba(0,0,0,0.5);" src="' + item.image + '"><h6 class="item-title">' + item.rus_representation + ' "' + item.brand + '"<hr></h6><p class="flex" style="align-items: flex-start"><span class="price-tag">' + item.price + ' $</span><span class="discount badge badge-danger">' + item.discount + ' $</span></p><button type="button" class="item-btn btn-sm btn btn-outline-info" data-toggle="modal" data-target=".details-modal">Подробней <img style="height: 10px" "></button></div>';
}
$('.items-list').children('hr').after(el)
});
}
})
});
使用相关数据填充模式的Java Script函数:
$(document).on('click', '.item-btn', function () {
var data = JSON.parse($(this).siblings('input').val()); (line 54 where error message points)
$('.product-title').html(data.rus_representation + ' "<i>' + data.brand + '</i>"' + '<hr>');
if(data.description) {
$('.product-description').text(data.description);
}else{
$('.product-description').html('<h4>Описнаие пока не добавлено</h4>')
}
$('.carousel-inner').empty();
$.each(data.images, function (index, img) {
if(index === 0){
var el = '<div class="carousel-item active"><img class="d-block w-100" src="'+ img +'"></div>'
} else {
var el = '<div class="carousel-item"><img class="d-block w-100" src="'+ img +'"></div>'
}
$('.carousel-inner').append(el)
});
$('.product-brand').html('<i>' + data.brand + '</i>');
$('.product-type').text(data.rus_representation);
$('.product-season').text(data.season);
if (data.discount){
$('.discount-in-modal').html('<span class="discount badge badge-danger" style="position: relative; top: -5px">'+ data.discount +' $</span>');
}
$('.product-price').text(data.price);
});
HTML:
{% for item in object_list %}
<div class="item-block flex" style="flex-direction: column">
<input type="hidden" value="{{ item.dumped_as_dict }}">
<img class="img-fluid" style="box-shadow: 0 0 10px rgba(0,0,0,0.5); max-height: 300px" src="{{ item.image.url }}">
<h6 class="item-title">
{{item.rus_representation}} "{{item.brand}}"
<hr>
</h6>
<p class="flex" style="align-items: flex-start">
<span class="price-tag">{{ item.price }} $</span>
{% if item.discount %}
<span class="discount badge badge-danger">{{ item.discount }} $</span>
{% endif %}
</p>
<button type="button" class="item-btn btn-sm btn btn-outline-info" data-toggle="modal" data-target=".details-modal">Подробней <img style="height: 10px" src="{% static 'img/arrow.png' %}"></button>
</div>
{% endfor %}
如果愿意console.log(JSON.stringify(item));
:
{"title":"tst","image":"/media/img/_58A1259_sm.jpg","brand":"GUCCI","type":"SK","discount":9000000,"price":9,"rus_representation":"Юбка","description":"LoL Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.","season":"","images":["/media/img/_58A1259_sm.jpg","/media/img/_58A7975_sm.jpg"]}
应如何显示:
opening the modal on initial load
我所拥有的:
if use filtering and them trying to open details modal
从检查器添加视图:
For some reasons string is not fully added to value
attr
答案 0 :(得分:0)
构建该HTML字符串时,您的代码将执行以下操作:
var el = '<div ... value=' + JSON.stringify(x) + ' ... >';
因此,HTML结果将为
var el = '<div ... value={ ... } ... >';
由于结果HTML源中未引用“值”的属性值,因此就HTML解析器而言,JSON中的第一个空格字符是属性值的结尾。
您至少需要包含引号:
var el = '<div ... value=\'' + JSON.stringify(x) + '\' ... >';
我也强烈建议您使用HTML实体编码器对字符串中的所有HTML元字符进行编码,例如
function scrubHtml(s) {
return s.replace(/[<>'"&]/g, function(meta) {
return "&#" + meta.charCodeAt(0) + ";";
});
}