I am stuck on a problem I am having trying to implement a 'Like' button into my django application.
I have the functionality working for the models, and even in the html template the code works if I manually add a like from a user.
It seems like my Ajax may be the issue, but I can't seem to figure out why.
Here is my models.py:
class Post(models.Model):
direct_url = models.URLField(unique=True)
post_url = models.URLField()
post_title = models.CharField(max_length=300)
time_posted = models.DateTimeField(default=timezone.now)
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Like(models.Model):
liker = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='likes')
date_created = models.DateTimeField(default=timezone.now)
def save(self, *args, **kwargs):
super(Like, self).save(*args, **kwargs)
And here is my views.py
class PostListView(LoginRequiredMixin, generic.ListView):
model = Post
template_name = 'homepage/home.html'
ordering = ['-time_posted']
context_object_name = 'posts'
paginate_by = 6
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['now'] = datetime.now()
context['likesbyuser'] = Like.objects.filter(liker=self.request.user)
return context
def likePost(request):
if request.method == 'GET':
post_id = request.GET['post_id']
likedpost = Post.objects.get(pk=post_id) # getting the liked post
if Like.objects.filter(post=likedpost, liker=request.user).exists():
Like.objects.filter(post=likedpost, liker=request.user).delete()
else:
m = Like(post=likedpost, liker=request.user) # creating like object
m.save() # saves into database
return HttpResponse(likedpost.likes.count())
else:
return HttpResponse("Request method is not a GET")
This is part of the template, where I am putting the buttons to use the Ajax which should call the like function:
{% for i in post.likes.all %}
{% if user == i.liker %}
<a class='likebutton' data-catid="{{ post.id }}"><i id='like{{ post.id }}' class="btn fas fa-heart fa-lg post-buttons "></i></a>
{% elif forloop.last %}
<a class='likebutton' data-catid="{{ post.id }}"><i id='like{{ post.id }}' class="btn far fa-heart fa-lg post-buttons "></i></a>
{% endif %}
{% empty %}
<a class='likebutton' data-catid="{{ post.id }}"><i id='like{{ post.id }}' class="btn far fa-heart fa-lg post-buttons "></i></a>
{% endfor %}
{% endfor %}
And here is the Ajax code I am adding to the base.html in script tags.
<script type="text/javascript">
$('main').on('click', '.likebutton', function(){
var catid;
catid = $(this).attr("data-catid");
$.ajax(
{
type:"GET",
url: "/likepost/",
data:{
post_id: catid
},
success: function(data){
if(data==0){
$('.like' + catid).toggle();
$('#like' + catid).toggleClass("far fas");
$('#likecount' + catid).html('');
console.log(data+'if');
}
else if(data==1){
if($('.like' + catid).is(":hidden"))
{
$('.like' + catid).toggle();
}
$('#like' + catid).toggleClass("far fas");
$('#likecount' + catid).html(data + ' like');
console.log(data+'elseif');
}
else{
$('#like' + catid).toggleClass("far fas");
$('#likecount' + catid).html(data + ' likes');
console.log(data+'else');
}
}
})
});
</script>
I have tried adding event.preventDefault(); to the ajax call, but that did not fix my issue.
I found the issue.
I was pointing the Ajax code at "main" as seen in the following snippet:
...
<script type="text/javascript">
$('main').on('click', '.likebutton', function(){
...
My issue was that I forgot to surround the block with the main tag when I ported this project over.
In my base.html I added the following code:
<main role="main" class="container h-100">
{% block content %}
{% endblock content %}
</main>
This fixed the issue.
Related
I am trying to build a form that allows users to provide a review of an area they have visited However, every iteration of trying to link the review to the beach model proves to be wasted effort.
Could someone please tell me why I can't get the form to show. I am consistently getting an error:
Reverse for 'beaches-review' with arguments '('',)' not found. 1 pattern(s) tried: ['review/(?P<beach_id>[0-9]+)/$']
or some variation of that.
My code is below. Thank you for any help you can provide.
Models.py
class Beach(models.Model):
name = models.CharField(max_length=80)
location = models.CharField(max_length=200)
video = models.FileField(upload_to='beachvideo', blank=True)
beachPic = models.ImageField(default='default.jpg', upload_to='beachphotos', blank=True)
datetimeInfo = models.DateTimeField(auto_now=True)
lat = models.FloatField()
lon = models.FloatField()
info = models.TextField()
def average_rating(self):
all_ratings = map(lambda x: x.rating, self.review_set.all())
return np.mean(all_ratings)
def __str__(self):
return f'{self.name}'
class Review(models.Model):
RATING = (
('1', 'Avoid'),
('2', 'Not Great'),
('3', 'Decent'),
('4', 'Awesome'),
('5', 'The Best'),
)
beach = models.ForeignKey(Beach, on_delete= models.CASCADE)
author = models.ForeignKey(User, null=True, blank=True, on_delete= models.CASCADE)
ratingRank = models.CharField(max_length= 100, blank=False, choices=RATING)
waveIntensityRank = models.CharField(max_length= 100, blank=True, choices=RATING)
crowdednessRank = models.CharField(max_length= 100, blank=True, choices=RATING)
pollutionRank = models.CharField(max_length= 100, blank=True, choices=RATING)
noiseLevelRank = models.CharField(max_length= 100, blank=True, choices=RATING)
servicesRank = models.CharField(max_length= 100, blank=True, choices=RATING)
comments = models.TextField(max_length=250, blank=True)
pub_date = models.DateTimeField(auto_now=True)
def get_absolute_url(self):
return reverse('beaches-home')
def __str__(self):
return self.author.username
Forms.py
class ReviewForm(forms.ModelForm):
class Meta():
model = Review
fields = ('ratingRank', 'author', 'waveIntensityRank', 'crowdednessRank', 'pollutionRank', 'noiseLevelRank', 'servicesRank', 'comments')
Urls.py
urlpatterns = [
path('', views.beachView, name='beaches-home'),
path('beach/<int:pk>', views.beachDescription, name='beaches-description'),
path('search/', views.searchResultsView.as_view(), name='search-results'),
path('review/<int:beach_id>/', views.addReview, name='beaches-review'),
]
Views.py
def beachView(request):
beachView = {
'beachView': Beach.objects.all()
}
return render(request, 'beaches/index.html', context = beachView)
def beachDescription(request, pk):
beachDesc = {
'beachDesc': Beach.objects.get(pk=pk)
}
return render(request, 'beaches/description.html', context = {'beachDesc': beachDesc} )
def review_list(request):
latest_reviews = Review.objects.order_by('-pub_date')[:9]
def addReview(request, beach_id):
beachRev = get_object_or_404(Beach, pk=beach_id)
if request.method == 'POST':
review_form = ReviewForm(data=request.POST)
if review_form.is_valid():
rating = review_form.cleaned_data['rating']
comment = review_form.cleaned_data['comments']
user_name = review_form.cleaned_data['author']
wave_intensity = review_form.cleaned_data['waveIntensityRank']
crowds = review_form.cleaned_data['crowdednessRank']
pollution = review_form.cleaned_data['pollutionRank']
noise_level = review_form.cleaned_data['noiseLevelRank']
services = review_form.cleaned_data['servicesRank']
review = Review()
review.beach = beachRev
review.author = user_name
review.rating = rating
review.waveIntensityRank = wave_intensity
review.crowdednessRank = crowds
review.pollutionRank = pollution
review.noiseLevelRank = noise_level
review.servicesRank = services
review.comments = comment
review.pub_date = datetime.datetime.now()
review.save()
return HttpResponseRedirect(reverse("beaches-description", args=(beach_id,)))
#if request.method == "POST":
#review_form = review_form(data=request.POST)
#if review_form.is_valid():
# rating = review_form.cleaned_data
# post.date = timezone.now()
# post.save()
# return redirect('beaches/beachReview.html')
#else:
# form=ReviewForm()
return render(request, 'beaches/beachReview.html', context= {'review_form': review_form, 'beachRev': beachRev,})
class searchResultsView(ListView):
model = Beach
template_name = 'beaches/searchResults.html'
def get_queryset(self): # new
query = self.request.GET.get('q')
object_list = Beach.objects.filter(
Q(name__icontains=query) | Q(location__icontains=query)
)
return object_list
HTML
{% extends 'base.html' %}
{% load static %}
{% block content %}
<head>
<link rel="stylesheet" href="{% static 'css/bestbeach.css' %}">
</head>
<h1> {{ beachDesc.name }} </h1>
<h4> Location: {{ beachDesc.location }} </h4>
<h4> Rating: {{ beachDesc.ratingRank }} </h4>
<table>
<tr>
<td> <img src="{{ beachDesc.beachPic.url }}" width="350px" height="200px"/> </td>
</tr>
<tr>
<td> <video width="350px" height="200px" loop="loop" preload="auto" controls>
<source src="{{ beachDesc.video.url }}" type="video/mp4">
Your browser does not support the video.
</video>
</td>
</tr>
</table>
<h4> Information: {{ beachDesc.info }} </h4>
<a href="{% url 'beaches-review' beach_id %}">
<button class="goButton" type="submit">Leave a Review</button>
</a>
{% if review_list %}
<div>
{% for r in review_list %}
<div>
<h4> Reviews: </h4>
<p> {{ r.author }} </p>
<h6> rated {{ r.rating }} of 5 </h6>
<p>{{ r.comments }}</p>
</div>
{% endfor %}
</div>
{% else %}
<p>No reviews are available.</p>
{% endif %}
{% endblock %}
Just to sanitize #ha-neul's comment.
You expose a Beach object using the beachDescription view, providing the template variable beachDesc.
beachDesc now hold all the attributes of the object's model.
So to get the id you can do:
<a href="{% url 'beaches-review' beachDesc.id %}">
OR
<a href="{% url 'beaches-review' beachDesc.pk %}">
Alternatively
you could add the following method to your Beach model
def get_absolute_beach_review_url(self):
return reverse('beaches-review', kwargs={'beach_id':self.id})
and link beachDesc.get_absolute_beach_review_url in your template.
I have followed a tutorial to utilise AJAX to validate an input field before attempting to submit. I have it working on my django built site; however, I have been using toasts to alert the user to other actions and did not want to get way from this.
$("#id_hub_name").focusout(function (e) {
e.preventDefault();
// get the hubname
var hub_name = $(this).val();
// GET AJAX request
$.ajax({
type: 'GET',
url: "{% url 'validate_hubname' %}",
data: {"hub_name": hub_name},
success: function (response) {
// if not valid user, alert the user
if(!response["valid"]){
alert("You cannot create a hub with same hub name");
var hubName = $("#id_hub_name");
hubName.val("")
hubName.focus()
}
},
error: function (response) {
console.log(response)
}
})
})
This is my current JS, I want to change the alert function to use toasts instead.
In my base.html I use the following to listen for toasts and create them.
{% if messages %}
<div class="message-container">
{% for message in messages %}
{% with message.level as level %}
{% if level == 40 %}
{% include 'includes/toasts/toast_error.html' %}
{% elif level == 30 %}
{% include 'includes/toasts/toast_warning.html' %}
{% elif level == 25 %}
{% include 'includes/toasts/toast_success.html' %}
{% else %}
{% include 'includes/toasts/toast_info.html' %}
{% endif %}
{% endwith %}
{% endfor %}
</div>
{% endif %}
Thanks in advance
You just need to append the html element for the toast.
First of all, loose the {% if messages %}, make sure <div class="message-container"> is always present in your template. If there are no messages, it will just be an empty div.You also need to add the templates for the toasts in js as well, so that you can just append the toasts from JS.
Now you can just append the template for the toast after your ajax response.
something like:
function show_alert_from_js(alert_type, text) {
msg = `<<your template here>>${text}`; // to render the text message to show.
msg_html = $.parseHTML(msg);
$('.message-container').append(msg_html);
}
$.ajax({
type: 'GET',
...
success: function (response) {
if(!response["valid"]){
show_alert_from_js("error", "You cannot create a hub with same hub name")
...
})
I am working on a school project where I have to program a REST API application that interacts with a database with basic POST and DELETE operation:
Here is my Python Flask file:
from flask import Flask, render_template, redirect, url_for, jsonify, request, Response, abort
from flask_bootstrap import Bootstrap
import dbinteraction
app = Flask(__name__)
Bootstrap(app)
#app.route('/')
def hello_world():
return redirect(url_for('index'))
#app.route('/index')
def index():
return render_template('index.html')
#app.route('/allrecipes')
def allrecipes():
return render_template('allrecipes.html')
#app.route('/ingredients')
def ingredients():
return render_template('ingredients.html')
#app.route('/api/v1.0/recipes', methods=['GET'])
def get_recipes():
# init
recipes = []
# get the task list from the db
recipes_list = dbinteraction.getRecipes()
# prepare the task list for jsonify
for item in recipes_list:
recipe = prepare_for_json(item)
recipes.append(recipe)
# return the task data
return jsonify({'recipes': recipes})
#app.route('/api/v1.0/ingredients', methods=['GET'])
def get_ingredients():
# init
ingredients = []
# get the user_ingredients list from the db
ingredients_list = dbinteraction.getIngredients()
# prepare the user_ingredients list for jsonify
for item in ingredients_list:
ingredient = prepare_for_json_ingredient(item)
ingredients.append(ingredient)
# return the ingredients data
return jsonify({'ingredients': ingredients})
#app.route('/api/v1.0/ingredients', methods=['POST'])
def insert_ingredient():
# get the request body
add_request = request.json
# check whether an ingredient is present or not
if (add_request is not None) and ('name' in add_request) and ('quantity' in add_request):
text = add_request['name']
quantity = add_request['quantity']
# insert in the database
dbinteraction.insertIngredients(text, quantity)
return Response(status=201)
# return an error in case of problems
abort(403)
#app.route('/api/v1.0/ingredients/<string:ing_name>', methods=['DELETE'])
def delete_ingredient(ing_name):
# delete the ingredient
ingredient = dbinteraction.removeIngredient(str(ing_name))
return Response(status=200)
def prepare_for_json(item):
"""
Convert the recipe in a dictionary for easing the JSON creation
"""
recipe = dict()
recipe['name'] = item[0]
recipe['link'] = item[1]
recipe['difficulty'] = item[2]
return recipe
def prepare_for_json_ingredient(item):
"""
Convert the ingredient in a dictionary for easing the JSON creation
"""
ingredient = dict()
ingredient['name'] = item[0]
ingredient['quantity'] = item[1]
return ingredient
if __name__ == '__main__':
app.run(debug=True)
I also programmed and tested the dbinteraction functions for the database and they work fine. My problem is in the ingredients.html part. I load and see the page as I want, a modifiable list of ingredients with the delete button. But when I click on the delete I get a Uncaught ReferenceError: (name of the ingredient) is not defined at HTMLAnchorElement.onclick
This are my html and javascript files:
{% extends "bootstrap/base.html" %}
{% block title %}All recipes page{% endblock %}
{% block styles %}
{{super()}}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.12/css/all.css"
integrity="sha384-G0fIWCsCzJIMAVNQPfjH08cyYaUtMwjJwqiRKxxE/rx96Uroj1BtIQ6MLJuheaO9" crossorigin="anonymous">
{% endblock %}
{% block scripts %}
{{ super() }}
<script src="{{ url_for('static', filename='kima2js.js') }}"></script>
{% endblock %}
{% block content %}
<div class="container" style="text-align: center">
<h1><i class="fas fa-utensils" style=""></i><br>
Insert an ingredient:
</h1>
<div id="ingredients_list" class="form-inline"></div>
<div id="insertingredient">
<form id="addForm"class="form-inline" method="POST">
<div class="form-group">
<label for="ingredientName">Ingredient:</label>
<input type="text" id="ingredientName" class="form-control" name="name"/>
</div>
<div class="form-group">
<label for="ingredientQuantity">Quantity:</label>
<input type="text" id="ingredientQuantity" class="form-control" name="quantity"/>
</div>
<button type="submit" class="btn-sm">Add</button>
</form>
</div>
</div>
{% endblock %}
... the javascript:
function addIngredient() {
$("#ingredients_list ul").empty();
$("#ingredientName").val('');
$("#ingredientQuantity").val('');
getIngredients();
}
function getIngredients() {
$.getJSON("http://127.0.0.1:5000/api/v1.0/ingredients", function(data){
var ingredients = data["ingredients"];
var len = ingredients.length;
for(var i = 0 ; i<len ; i++) {
var t = ingredients[i];
$("#ingredients_list ul").append("<li class='list-group-item list-group-item-text'>"+t.name+" "+t.quantity
+" <a class='delete btn btn-default' onclick='deleteIngredient("+ t.name +")'>" +
" <span class='glyphicon glyphicon glyphicon-remove'></span>Delete</a></li>");
}
});
}
function deleteIngredient(ing_name) {
$.ajax("/api/v1.0/ingredients/"+ing_name,
{
method: 'DELETE',
success: function (status) {
// update the list of printed ingredients: called when the DELETE is complete
getIngredients();
}
}
);
}
$(document).ready(function () {
$("#ingredients_list").append("<ul></ul>");
$("#ingredients_list ul").empty();
getIngredients();
$("#addForm").submit( function(){
var name = $("#ingredientName").val();
var quantity = $("#ingredientQuantity").val();
var ingredient = {'name': name, 'quantity': quantity};
var json = JSON.stringify(ingredient);
$.post({
"url": "http://127.0.0.1:5000/api/v1.0/ingredients",
"data": json,
"contentType":"application/json",
"success": addIngredient
});
return false;
});
});
I can't see what I am doing wrong. My only guesses are on the onclick part. Because I have tested singularly all the other pieces of code in previous labs
You just need to make sure that the value of ing_name is in quotes when you write it as a parameter to onclick, as follows:
$("#ingredients_list ul").append("<li class='list-group-item list-group-item-text'>"+t.name+" "+t.quantity
+" <a class='delete btn btn-default' onclick='deleteIngredient(\""+ t.name +"\")'>" +
" <span class='glyphicon glyphicon glyphicon-remove'></span>Delete</a></li>");
Otherwise javascript thinks ing_name is a variable name (and the variable is not defined).
Hello Awesome People!
So many questions on StackOverflow are about "How to refresh dom via jquery (from the same view/url)" It's not what I'm looking for.
With a website that large of its parts are running with ajax, I wonder how to refresh a part of the HTML DOM when querying a foreign django view.
Let me be clearer with some examples:
I have that view that sends all_users to template
def usersList(request):
all_users = User.objects.all()
return render(request,'administration/users-list.html',{'all_users':all_users})
In the template I loop through all_users... The 2nd <span> reflects the activation state of the user
{% for u in all_users %}
<span>{{forloop.counter}}.- {{u.name}} <span>
<span id='user_{{u.id}}_state'>
<button data-id='{{u.id}}' type='button' class='css-btn btn-circle'>
{% if u.is_activate %} Active{% else %}Inactive{% endif %}
</button>
<span>
{% endfor %}
With jquery, I send a request to a specific view responsible only to activate or deactivate the account of the user. We can activate/deactivate user in many parts of the website, that's why I do so in a different view.
Here's the view:
def deactivateUser(request):
user = request.user
if user.has_perm('is_admin') and request.is_ajax() and request.method == 'POST':
id_user = request.POST.get('id')
targeted_user = get_object_or_deny(User,id=id_user)
# get_object_or_deny is my own function
it will get the object or raise PermissionDenied otherwise
if targeted_user.is_activate:
targeted_user.is_activate = False
state = 'deactivated'
else:
targeted_user.is_activate = True
state = 'activated'
targeted_user.date_update_activation = NOW() # own function
targeted_user.save()
return JsonResponse({'done':True,'msg':'User successfully %s' %s state})
# Here we return a JsonResponse
raise PermissionDenied
So now, how can I refresh the Dom with following jquery stuff to get the current state of each user
$(document).on('click','.btn-circle',function(){
var id = $(this).data("id");
$.ajax({
url:'/u/de-activate/?ref={{ request.path }}',
type:'post',
data:{
csrfmiddlewaretoken:"{{ csrf_token }}",
id:id,
},
success:function(response){
$("#user_"+id+"_state").replaceWith($("#user_"+id+"_state",response));
if(response.created) alert(response.msg);
},
error:function(){
alert("An error has occured, try again later");
}
});
});
Note that all_users is required to loop through. deactivateUser() return a Json response, even though it doesn't returned it, it will not matter.
You can send http response, not json.
First, just move your html that want to change. in this situation,
{% for u in all_users %}
<div id="user-part">
<span>{{forloop.counter}}.- {{u.name}} <span>
<span id='user_{{u.id}}_state'>
<button data-id='{{u.id}}' type='button' class='css-btn btn-circle'>
{% if u.is_activate %} Active{% else %}Inactive{% endif %}
</button>
<span>
</div>
{% endfor %}
Then save it i.e. user_part.html
Second, make your view return HttpResponse with that html, and context. You can use either HttpResponse or render_to_response. I recommend render_to_response.
context = {
'all_users': all_users,
}
return render_to_response(
'path_to/user_part.html',
context=context,
)
Third, you just change script for replacing your html.
success: function(response){
$('#user-part').html(response);
prevent();
}
The .html file is
<tbody>
{% for row in results %}
<tr class="{% cycle 'row1' 'row2' %} clickable-row" data-href="{% url "perception:detail" pk=row.object.pk %}">
{% for item in row.cols %}
{{ item }}
{% endfor %}
{% if row_actions_template %}
<td class="row-actions">{% include row_actions_template with object=row.object %}</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
The .js file is
$(function(e){
$(".clickable-row").click(function() {
window.location = $(this).data("href");
});
});
The views.py file is
class PerceptionIndexView(StaffRestrictedMixin, FrontendListView):
page_title = _('Perception')
model = Perception
template_name = 'loanwolf/perception/index.html'
pjax_template_name = 'loanwolf/perception/index.pjax.html'
# row_actions_template_name = 'loanwolf/perception/list-actions.inc.html'
url_namespace = 'perception'
def active(self, obj):
if obj.is_active:
return icon(obj.get_icon(), css_class='green-text', tooltip=_('Active'))
else:
return icon(obj.get_icon(), css_class='red-text', tooltip=_('Inactive'))
def notes_count(self, obj):
return obj.notes.count()
notes_count_label = _('Notes')
def get_change_url(self, obj):
return obj.get_absolute_url()
class Meta:
ordering = ('-created', '-modified')
sortable = ('start_date', 'end_date', 'created', 'state', 'modified')
list_filter = ('state', 'is_active', customer, error)
list_display = (
'__unicode__', 'context_menu', 'state', 'start_date', 'end_date', 'current_balance',
'operation_error', 'modified', 'created', 'notes_count', 'active'
)
The part of the models.py file is
#python_2_unicode_compatible
class Perception(xwf_models.WorkflowEnabled, TimeStampedModel):
loan = models.ForeignKey('loans.Loan')
state = xwf_models.StateField(PerceptionWorkflow)
start_date = models.DateField(_('Start date'))
end_date = models.DateField(_('End date'), blank=True, null=True)
current_balance = models.DecimalField(_('Current balance'),
default=0, decimal_places=2, max_digits=11)
operation_error = models.SmallIntegerField(_('Operation error'), default=0)
notes = GenericRelation(Note)
def get_absolute_url(self):
return reverse('perception:detail', kwargs={'pk': self.pk})
def get_icon(self):
if self.is_active:
return 'check_circle'
else:
return 'remove_circle'
def save(self, *args, **kwargs):
rs = super(Perception, self).save(*args, **kwargs)
return rs
#Property
def __str__(self):
return six.text_type(_('Perception #%07d') % self.pk)
#property
def firstname(self):
first_name = self.loan.request.customer.user.first_name
return first_name
#property
def lastname(self):
last_name = self.loan.request.customer.user.last_name
return last_name
#property
def context_menu(self):
tpl = 'perception/context-menu.inc.html'
return mark_safe(render_to_string(tpl, {
'user': self.loan.request.customer.user,
'customer': self.loan.request.customer,
}))
The perception/context-menu.inc.html file looks like
{% load i18n %}
<div class="customer-context-menu closed {% if customer.gender == 0 %}male{% else %}female{% endif %}">
<b class="unselectable">
{{ customer.icon }}
{{ user.get_full_name }}
</b>
<ul>
<li class="tip"></li>
<li>{% trans "Profile" %}</li>
<li>{% trans "Alerts" %}</li>
<li>{% trans "Messaging" %}</li>
<li>{% trans "Requests" %}</li>
<li>{% trans "Documents" %}</li>
<li>{% trans "Logs" %}</li>
<li class="separator"></li>
{% if customer.phone_1 %}
<li class="phone">{{ customer.phone_1 }}</li>
{% endif %}
<li><i class="material-icons">email</i> {{ user.email }}</li>
<li><i class="material-icons">printer</i> {% trans "Print" %}</li>
</ul>
</div>
In the row image, I could click on the button associated to Randy Senger which open a little window with different options on the same page similar to enter image description here. Actually, there is a clickable-row associated to this row. The problematic is located when I clicked on the button. When I click on the button it opened the little window for approximately two seconds, and it render on another page a little as if I was clicking on the row. I think I could use a preventDefault on my .js file so that when I click on the button, it is not affected by clickable-row. Could anyone have an idea how I could modify my .js file to fix this?
P.S. Please let me know if the question is unclear.
What should be the issue here?
$(function(e){
$(".clickable-row").on('click', function() {
window.location = $(this).data("href");
});
});
$(".customer-context-menu").on('click', function(e) {
e.preventDefault();
e.stopPropagation();
});
Unfortunately, I know nothing of Python. But it seems though, that your problem is about firing events for wrapping elements on your DOM. This is related to event bubbling.
Should you bind an event to a parent and a child, clicking on the child will fire both events, unless you specify the context where your event is supposed to execute.
event.stopPropagation should stop the event handling from being notified to the parent.
$('.child').on('click', function(){
e.stopPropagation();
console.log('only the child fires the event');
});
In any case, have you tried to retrieve the event.target of your jQuery event? It should be different according to where you click inside the parent.
<script>
$('.clickable-row').on('click', function(event){
// Every event returns an event object when specified as a callback parameter
console.log(event.target);
if ($(event.target).is('.my-class')){
// Do code for specific clicked element
}
});
</script>
I really hope this helps!