Jquery favorite function call api with ajax - javascript

I'm trying to create a favorite function in my django template that let user click on the icon and it will call to an api i made to send add and remove that favorite item from user data.
Currently how it work is if user click on the icon(favorite or unfavorite) it will call to an api that handle add favorite or remove favorite, and also it will replace the DOM of that tag with the opposite (for example if i click on favorite then the entire tag of it will be replace with tag content that has unfavorite icon and onclick function)
here my html for the tag, it display base on if it is favorite or not( {% %} tag is django handling it ):
<div class="article-category">{{ property.get_type_display }}
<div class="bullet"></div> {{ property.publish_date|date:'d-m-Y' }}
{% if not request.user|is_favorite:property.id %}
<a id="mylink" href="javascript:onclickFunction()" value="{{ property.id }}">
<i class="far fa-heart fa-lg" style="color: red" title="Add to favorite"></i>
</a>
{% else %}
<a id="mylink2" href="javascript:onclickFunction()" value="{{ property.id }}">
<i class="fas fa-heart fa-lg" style="color: red" title="Remove from favorite"></i>
</a>
{% endif %}
</div>
And here is my jquery script:
<script>
$(document).ready(function () {
$('#mylink').on('click', function (event) {
event.preventDefault();
property_id = $(this).attr("value")
$.ajax({
type: "POST",
url: "http://localhost:9999/api/add_favorite/" + property_id + "/",
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer {{ refresh_token }}');
},
success: function (data) {
if (data.code == 200) {
alert('ok');
replace_part_1 = '<a id="mylink2" href="javascript:onclickFunction()" value="' + property_id +'"><i class="fas fa-heart fa-lg" style="color: red" title="Remove from favorite></i></a>'
$("#mylink").replaceWith(replace_part_1);
}
}
});
return false;
});
$('#mylink2').on('click', function (event) {
event.preventDefault();
property_id = $(this).attr("value")
$.ajax({
type: "DELETE",
url: "http://localhost:9999/api/remove_favorite/" + property_id + "/",
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer {{ refresh_token }}');
},
success: function (data) {
if (data.code == 200) {
alert('ok');
replace_part_2 = '<a id="mylink" href="javascript:onclickFunction()" value="' + property_id +'"><i class="far fa-heart fa-lg" style="color: red" title="Add to favorite"></i></a>'
$("#mylink2").replaceWith(replace_part_2);
}
}
});
return false;
});
});
</script>
Now the first time i click on favorite or unfavorite it sent to the api and work, the replace html part for "#mylink2" onclick event but the "#mylink" replace doesn't include the tag which contain the icon.
After this any clicking event after that won't work and i have to refresh the page to click it again to work. Any click event after that also return this error:
Uncaught ReferenceError: onclickFunction is not defined
at :1:1
I'm super noob at jquery so i can't seem to find what is wrong, hope someone can help me
EDIT:
i changed my script to this by replace with value attribute of anchor tag:
<script>
$(document).ready(function () {
$('.article-details').on('click', '#mylink', function(event) {
event.preventDefault();
property_id = $(this).attr("value")
$.ajax({
type: "POST",
url: "http://localhost:9999/api/add_favorite/" + property_id + "/",
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer {{ refresh_token }}');
},
success: function (data) {
if (data.code == 200) {
alert('ok');
replace_part_1 = '<a id="mylink2" href="#" value="' + property_id +'"><i class="fas fa-heart fa-lg" style="color: red" title="Remove from favorite></i></a>'
$("a[value='" + property_id + "']").replaceWith(replace_part_1);
}
}
});
return false;
});
$('.article-details').on('click', '#mylink2', function(event) {
event.preventDefault();
property_id = $(this).attr("value")
$.ajax({
type: "DELETE",
url: "http://localhost:9999/api/remove_favorite/" + property_id + "/",
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer {{ refresh_token }}');
},
success: function (data) {
if (data.code == 200) {
alert('ok');
replace_part_2 = '<a id="mylink" href="#" value="' + property_id +'"><i class="far fa-heart fa-lg" style="color: red" title="Add to favorite"></i></a>'
$("a[value='" + property_id + "']").replaceWith(replace_part_2);
}
}
});
return false;
});
});
</script>
and my html to:
<div class="article-category">{{ property.get_type_display }}
<div class="bullet"></div> {{ property.publish_date|date:'d-m-Y' }}
{% if not request.user|is_favorite:property.id %}
<a id="mylink" href="#" value="{{ property.id }}">
<i class="far fa-heart fa-lg" style="color: red" title="Add to favorite"></i>
</a>
{% else %}
<a id="mylink2" href="#" value="{{ property.id }}">
<i class="fas fa-heart fa-lg" style="color: red" title="Remove from favorite"></i>
</a>
{% endif %}
</div>
it worked but the onclick of #mylink when changing the html the i tag inside still disappear(the #mylink2 onclick worked it changed the html white the tag)

It looks like you are facing an event delegation problem. That is, the moment your jQuery code runs, $('#mylink2') does not exist in the document and hence the event doesnt get binded. Use event delegation instead:
$('.article-category').on('click', '#mylink2', function(event) {
event.preventDefault();
// your original click handler
});
#myParentWrapper should be an element that is consistent in your markup, preferably not body or document for performance reasons.
You can then remove the onclick attribute from your anchor - or - actually somewhere define the function that is referenced there if it should do anything other than what your jQuery code does already.

Related

How to call an element in jquery when the ID of the element is stored in a variable?

Template
{% for question, count, is_follow in zipp %}
<div class="border rounded my-2 px-3 py-1" style="box-shadow: 2px 2px 5px #2b6dad;">
<p class="fst-normal">
<small>Tags: </small>
{% for tag in question.tags.all %}
<small><i>{{tag.name}} |</i></small>
{% endfor %}
</p>
<p><a href="{{question.get_absolute_url}}" style="text-decoration: none; color: black"><h5>{{ question.question }}</h5>
<small>Arguments added: {{ count }}</small></a></p>
<div class="blank" id="{{question.question_id}}">
{% include 'snippets/follow_question.html' %}
</div>
<button type="button" class="btn btn-secondary btn-sm mt-1"><i class="fa fa-share-alt" style="padding-right: 3px;"></i>Share</button>
</div>
{% endfor%}
Script
<script type='text/javascript'>
$(document).ready(function(event){
$(document).on('click', '#follow', function(event){
event.preventDefault();
var this_element = $(this)
var pk = $(this_element).attr('value');
$.ajax({
type: 'POST',
url: '{% url 'follow_question' %}',
data: {'id': pk, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
datatype: 'json',
success: function(response){
var id = $(this_element).closest('.blank').attr('id');
$('id').html(response['form']);
},
error: function(rs, e){
console.log(rs.responseText);
},
});
});
});
</script>
Inside the script, the ID of the element is stored in var id. I want to use that ID to change its html as I was trying to do in the next line but it's not working. How can I do that?
You are looking for an associated element to get it's id to use to look for that same element again.
That is redundant when you can just use the reference to the closest element itself
Simplified version:
this_element.closest('.blank').html(response['form'])
Why not
var id = $(this_element).closest('.blank').attr('id');
$(`#${id}`).html(response['form']); // $('#' + id)

How to change fontawsome class name with ajax?

I want to change the icon after deleting row. Should I only use font awesome icon once in blade, then remove the class name, then add the class name with ajax?
blade:
<div id="status-{{ $country->id }}">
<div id="icon-{{$country->id}}">
#if( getStatus($country->status) == 'Active' || getStatus($country->status) == 'Aktif' )
<i class="fa fa-check-circle text-success"></i>
#elseif( getStatus($country->status) == 'Inactive' || getStatus($country->status) == 'Pasif' )
<i class="fas fa-minus-circle text-info"></i>
#else
<i class="fas fa-times-circle text-danger"></i>
#endif
<strong>{{ getStatus($country->status) }}</strong>
</div>
</div>
ajax:
$.ajax({
url: url,
type: "DELETE",
header: {
_token: "{{ csrf_token() }}",
},
success() {
toastr['error']("{{ __('home.delete.message') }}");
swal("{{ __('home.delete.message') }}", {
icon: "success",
});
$('#status-' + id).text('Deleted')
$('#icon-' + id).attr('i').addClass('fas fa-times-circle text-danger')
},
error(error) {
toastr['warning']("{{ __('home.error.message') }}");
}
});
JQuery's .attr() function is used to change the element's attribute. It has nothing to do with it's children.
Replace
$('#icon-' + id).attr('i').addClass('fas fa-times-circle text-danger')
with this
$('#icon-' + id + ' i').eq(0).attr('class', 'fas fa-times-circle text-danger');

Need to hide whole table row when click on delete button in jQuery [duplicate]

This question already has answers here:
$(this) inside of AJAX success not working
(2 answers)
Closed 2 years ago.
I'm working on an application by using jquery ajax mathod and trying to delete table row by clicking on delete button. The backend part of php is fine but what i'm trying to apply is hide or fadeOut() jquery method on click event but unable to get the result. See following code:
$('.deletePageBtn').on('click', function(e) {
e.preventDefault();
if (confirm('Do you really want to delete this page?')) {
var pageId = $(this).data("pageid");
$.ajax({
url: "<?= base_url('admin/pagemanagerSavePage')?>",
type: 'POST',
data: {
action: "delete-page",
pageId: pageId
},
success: function(data) {
if (data == 'success') {
$(this).parent().parent().remove();
}
console.log(data);
},
error: function(data) {
console.log(data);
}
});
};
});
<tr id="rowId_26" class="rowData odd" role="row">
<td class="text-center sorting_1">3</td>
<td class="bg-success text-light text-center">
<i class="fas fa-eye"></i>
</td>
<td>
Pawan Mall - Internet Geek 123
<div class="btn-group float-right">
<a href="#" class="btn btn-sm btn-primary" target="_blank">
<i class="fas fa-eye"></i> View Page
</a>
<a href="" id="editPage" class="btn btn-sm btn-warning">
<i class="fas fa-edit"></i> Edit Page
</a>
<a href="" data-pageid="26" class="btn btn-sm btn-danger deletePageBtn">
<i class="fas fa-trash"></i> Delete Page
</a>
</div>
</td>
</tr>
The issue here is inside ajax success:
success: function(data) {
if (data == 'success') {
$(this).parent().parent().remove();
}
console.log(data);
},
this refers to the jqXHR object of the Ajax call. Its not same $('.deletePageBtn') element anymore. To make this work you can cache this at start inside click event like:
var $this = $(this);
and then use it inside success like:
success: function(data) {
if (data == 'success') {
$this.parent().parent().remove();
}
console.log(data);
},
or, better:
success: function(data) {
if (data == 'success') {
$this.closest('tr').remove();
}
console.log(data);
},

Why Javascript event running multiple times per click?

I wrote a js-class which handles the Ajax-calls when a user clicks on a button. So the user can simply click on open/close and can open/close a entity in my database.
All works fine. The button-icon changes and the popover title and text changes also. The user can click on the buttons again and again and the Ajax does the work and jQuery changes the look - BUT -
When I watch in my debug bar - I see that with every click a additional Ajax call is running. When I click the button 3 times - the same Ajax-call will run 4 times for changing the entity to open/close.
I inspected the handlers. Every time it is only one handler and one #close-course element.
I really don't understand why this Ajax calls get more and more with every click!
Here my js-class:
'use strict';
import $ from "jquery";
(function (window, $) {
class CourseApp {
constructor($wrapper) {
this.$wrapper = $wrapper.find('.js-wrapper');
this.$body = $wrapper
this.iconBtn = this.$wrapper.find('a').blur();
this.$submitCount = 0;
this.$wrapper.on(
'click',
'a',
this.handleOpenCloseAction.bind(this)
);
}
handleOpenCloseAction(e) {
let popover = this.$body.find('.popover')
// prevent popover to close - when open-button is hitted
popover
.on('mousedown', '#open-course', function (e) {
e.preventDefault()
});
// prevent popover to close - when open-button is hitted
popover
.on('mousedown', '#close-course', function (e) {
e.preventDefault()
});
// since open-course-link is clicked - open the course and
// do some action
popover
.on(
'click',
'#open-course',
function (e) {
const $btn = $(e.currentTarget);
let $icon = $btn.find('.icon-lock-open');
if (this.$submitCount === 0) {
this.$submitCount++;
$.ajax({
url: $btn.data('open-course-url'),
method: 'POST',
}).then(function (data) {
$('[data-toggle="popover"]').popover('hide');
this.iconBtn.blur();
this.iconBtn.attr('data-content', data);
this.iconBtn.attr('data-original-title', 'Kurs schließen');
$('.icon-lock').removeClass('icon-lock').addClass('icon-lock-open');
}.bind(this))
this.$submitCount = 0;
}
}.bind(this)
)
// since close-course-link is clicked - close the course and
// do some action
popover
.on(
'click',
'#close-course',
function (e) {
const $btn = $(e.currentTarget);
if (this.$submitCount === 0) {
this.$submitCount++;
$.ajax({
url: $btn.data('close-course-url'),
method: 'POST',
}).then(function (data) {
$('[data-toggle="popover"]').popover('hide');
this.iconBtn.blur();
this.iconBtn.attr('data-content', data);
this.iconBtn.attr('data-original-title', 'Kurs öffnen');
$('.icon-lock-open').removeClass('icon-lock-open').addClass('icon-lock');
}.bind(this))
this.$submitCount = 0;
}
}.bind(this)
)
}
}
window.CourseApp = CourseApp;
})(window, jQuery);
My html:
<td class="col-1 js-wrapper">
<a href="#"
class="btn btn-primary pop"
data-content="{% if entity.open %} {{ popoverContentClose }} {% else %} {{ popoverContentOpen }} {% endif %}" data-toggle="popover" tabindex="0" data-trigger="focus"
title=""
data-original-title="{% if entity.open %} Kurs schließen? {% else %} Kurs öffnen? {% endif %}"
data-placement="left">
{% if entity.open %}
<i class="icon icon-lock-open"></i>
{% else %}
<i class="icon icon-lock"></i>
{% endif %}
</a>
</td>
The popover (is in a twig block):
Möchtest du diesen Kurs wirklich schließen? Die Teilnehmer dieses Kurses müssen somit jeden Kurszugang bestätigen.
<br>
<table class='table popover-table mb-0'>
<tr>
<td class='pl-0 border-top-0'>
<a href='#'
class='btn btn-danger-outline col-md-12 ml-0' id='close-course' data-close-course-url='{{ path('close_course', {'id' : entity.id}) }}'><i class='icon icon-lock'></i>Schließen</a>
</td>
<td class='pr-0 border-top-0'>
<button class='btn btn-primary col-md-12' class='close'
data-dismiss='alert'>{{ 'common.close'|trans }}</button>
</td>
</tr>
</table>

How to put <a href on that like which is 3? I'm using javascript

How to put an anchor tag <a href on that number 3 using javascript? Below is my source code:
$('.vote').click(function(e) {
e.preventDefault();
var product_id = $(this).data('product_id');
var voteCount = $(this).siblings('.vote_count');
$(this).siblings('a.vote').removeClass('active');
$(this).toggleClass('active');
if( !$(this).hasClass('active')){
$.get("{{ URL::route('unvote') }}", {product_id: product_id}).done( function(data){
console.log(data);
voteCount.text(data[0].vote_count);
});
} else {
if( $(this).hasClass('upvote')){
$.get("{{ URL::route('upvote') }}", {product_id: product_id}).done(function(data){
voteCount.text(data[0].vote_count);
});
} else {
$.get("{{ URL::route('downvote') }}", {product_id: product_id}).done( function(data){
voteCount.text(data[0].vote_count);
});
}
}
});
Below is image for reference, here under the price tag I want to put anchor tag:
Here's my view code:
if(Auth::check()) {
echo ' <div class="pull-left" style="margin-left:80px" > <a class="vote upvote" data-product_id="'.$products[$product]->product_id.'" href="hehehe"> <span class="fa fa-thumbs-up"></span> </a> '; } echo '<span class="vote_count"></span>'; if(Auth::check()) { echo '<a class="vote downvote" data-product_id="'.$products[$product]->product_id.'" href="#"> <span class="fa fa-thumbs-down"></span> </a> </div>';
}
The number 3 in your view is probably being rendered inside the following element:
<span class="vote_count"></span>
So why won't you wrap an a element around it?
</span>
Or you can do it dinamically with jQuery using wrap():
$(".vote_count").wrap("<a href=''></a>");

Categories

Resources