Toggle fa fa button is not changing when clicked - javascript

I am building a BlogApp and I am trying to make a like button which changes when clicked. BUT when i click on star button then it doesn't fill with color.
Like is successfully adding BUT star like button is not changing.
template.html
{% for i in p.likes.all %}
{% if user == i.liker %}
<a class='likebutton' data-catid="{{ p.id }}"><i id='like{{ p.id }}' class="btn fa fa-star-o fa-lg post-buttons "></i></a>
{% elif forloop.last %}
<a class='likebutton' data-catid="{{ p.id }}"><i id='like{{ p.id }}' class="btn fa fa-star-o fa-lg post-buttons "></i></a>
{% endif %}
{% empty %}
<a class='likebutton' data-catid="{{ p.id }}"><i id='like{{ p.id }}' class="btn fa fa-star-o fa-lg post-buttons "></i></a>
{% endfor %}
main.js
$('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).find('#like').toggleClass('fa-star-o fa-star');
$('#likecount' + catid).html('');
console.log(data+'if');
}
else if(data==1){
if($('.like' + catid).is(":hidden"))
{
$('.like' + catid).toggle();
}
$('#like' + catid).find('.like').toggleClass('fa-star-o fa-star');
$('#likecount' + catid).html(data + ' like');
console.log(data+'elseif');
}
else{
$('#like' + catid).toggleClass("far fas");
$('#likecount' + catid).html(data + ' likes');
console.log(data+'else');
}
}
})
});
main.css
:root {
font: 400 16px/1.5 Verdana;
}
.like {
display: inline-block;
font: inherit;
padding: 0px 5px;
cursor: pointer;
}
.like::after {
content: ' Favorite'
}
Any help would be much Appreicated. Thank You in Advance.

I think it's because #like element doesn't exist:
$('#like' + catid).find('#like').toggleClass('fa-star-o fa-star');
Maybe try:
$('#like' + catid).toggleClass('fa-star-o fa-star');

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');

Ajax like button not showing increment in count or else

I wanted to add like heart button with like count. I want to use ajax for changing likes count and color change. but when I tried to do that it won't work.
HTML
<div id="posts">
{% for post in page_obj %}
<div><a >{{ post.userp }}</a></div>
<div>{{ post.content }}</div>
<div>{{ post.timestamp }}</div>
<div id="post_name">
{% if request.user in post.userl.all %}
<a class="likeu" style="cursor: pointer"><span id="{{ post.id }}" class="likeu1" style="font-size:24px;color:red">♥</span></a>
{% else %}
<a class="likeu" style="cursor: pointer"><span id="{{ post.id }}" class="likeu1" style="font-size:24px;color:grey">♥</span></a>
{% endif %}
<p id="{{ post.id }}l">{{ post.userl.all.count }}</p>
</div>
<hr>
{% endfor %}
</div>
and JAVASCRIPT
document.querySelectorAll('.likeu1').forEach(element => element.addEventListener('click', change_like));
function change_like(){
post_id = this.id
console.log(post_id)
fetch('/likes', {
method: 'POST',
body: JSON.stringify({
post_id : post_id,
})
})
.then(response => response.json())
.then(result => {
value = result["is_liked"];
console.log(value);
console.log(this);
if (value == 'true'){
this.style.color = 'red';
console.log('red');
}
else{
this.style.color = 'grey';
console.log('grey');
}
})
}
It is updating when I refresh but I want it without refresh.
I don't know what I am doing wrong. please help!

Jquery favorite function call api with ajax

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.

Shopify mini cart show number of products not total amount

I am using Shopify and want the minicart to show the number of products/items, not the total of the cart. For example if I sell 3 metres of one fabric and then 4 metres of another fabric then it says 2 not 7.
I have managed to amend the header coding with cart.items.size (instead of cart.item_count) and this works fine when a page first loads. However if I am on a product page and add products, the mini cart updates but it counts the total again, not the number of fabrics. If I refresh the page then it is fine again.
I have tried editing the javascript to read cart.items.size instead of cart.item_count, but it just comes up with 'undefined' when the items are added to the cart.
I have no experience of editing javascript so can someone point me in the right direction please. If you need any extra code or information please do say, apologies if I miss anything.
Here is the header code that is working:
<div class="mini-cart-wrap" href="#">
{% if settings.cart-icon == "cart" %}
{% include 'icon' with 'cart' %}
{% else %}
{% include 'icon' with 'bag' %}
{% endif %}
<label><span class="item-count">{{ cart.items.size }}</span> {{ 'layout.header.item_count' | t: count: cart.items.size }}</label>
<div class="mini-cart {% if shop.customer_accounts_enabled %}account-enabled{% endif %} {% if cart.items.size == 0 %}empty-cart{% endif %}">
<div class="arrow"></div>
<div class="mini-cart-items-wrap">
<p class="no-items">{{ 'layout.header.no_items' | t }}</p>
{% for item in cart.items %}
<div id="item-{{ item.id }}" class="item clearfix">
<div class="image-wrap">
<img alt="{{ item.product.title }}" src="{{ item | img_url: 'small' }}">
<a class="{% if settings.product-image-borders %}overlay{% endif %}" href="{{ item.url }}"></a>
</div>
<div class="details">
{% if settings.show-brand-names %}
<p class="brand">{{ item.vendor | link_to_vendor }}</p>
{% endif %}
<p class="title">{{ item.product.title }}<span class="quantity">× <span class="count">{{ item.quantity }}</span></span></p>
<p class="price"><span class="money">{{ item.line_price | money }}</span></p>
{% unless item.variant.title == 'Default Title' %}<p class="variant">{{ item.variant.title }}</p>{% endunless %}
{% if item.properties %}
{% for property in item.properties %}
{% unless property.last == blank %}
<p class="property">
<span class="property-label">{{ property.first }}:</span>
{% if property.last contains '/uploads/' %}
<a class="property-image" href="{{ property.last }}">{{ property.last | split: '/' | last }}</a>
{% else %}
<span class="property-value">{{ property.last }}</span>
{% endif %}
</p>
{% endunless %}
{% endfor %}
{% endif %}
</div>
</div>
{% endfor %}
</div>
<div class="options clearfix">
<a class="action-button view-cart desaturated" href="/cart">{{ 'layout.header.view_cart' | t }}</a>
<a class="action-button checkout" href="/checkout">{{ 'layout.header.checkout' | t }}</a>
</div>
</div>
</div>
And here is the current javascript (unedited)
ProductView.prototype.updateMiniCart = function(cart) {
var i, item, itemProperties, itemText, j, len, miniCartItemsWrap, productPrice, propertiesArray, propertyKeysArray, ref, variant;
miniCartItemsWrap = $(".mini-cart-items-wrap");
miniCartItemsWrap.empty();
if (cart.item_count !== 1) {
itemText = Theme.cartItemsOther;
} else {
itemText = Theme.cartItemsOne;
$(".mini-cart .options").show();
miniCartItemsWrap.find(".no-items").hide();
}
$(".mini-cart-wrap label").html("<span class='item-count'>" + cart.item_count + "</span> " + itemText);
ref = cart.items;
for (j = 0, len = ref.length; j < len; j++) {
item = ref[j];
productPrice = Shopify.formatMoney(item.line_price, Theme.moneyFormat);
variant = item.variant_title ? "<p class='variant'>" + item.variant_title + "</p>" : "";
itemProperties = "";
if (item.properties) {
propertyKeysArray = Object.keys(item.properties);
propertiesArray = _.values(item.properties);
i = 0;
while (i < propertyKeysArray.length) {
if (propertiesArray[i].length) {
itemProperties = itemProperties + ("<p class=\"property\">\n <span class=\"property-label\">" + propertyKeysArray[i] + ":</span>\n <span class=\"property-value\">" + propertiesArray[i] + "</span>\n</p>");
}
i++;
}
}
miniCartItemsWrap.append("<div id=\"item-" + item.variant_id + "\" class=\"item clearfix\">\n <div class=\"image-wrap\">\n <img alt=\"" + item.title + "\" src=\"" + item.image + "\">\n <a class=\"overlay\" href=\"" + item.url + "\"></a>\n </div>\n <div class=\"details\">\n <p class=\"brand\">" + item.vendor + "</p>\n <p class=\"title\">" + item.product_title + "<span class=\"quantity\">× <span class=\"count\">" + item.quantity + "</span></span></p>\n <p class=\"price\"><span class=\"money\">" + productPrice + "</span></p>\n " + variant + "\n " + itemProperties + "\n </div>\n</div>");
}
if (Theme.currencySwitcher) {
return $(document.body).trigger("switch-currency");
}
};
and also here (for the quick view)
ProductView.prototype.updateMiniCart = function(cart) {
var i, item, itemProperties, itemText, j, len, miniCartItemsWrap, productPrice, propertiesArray, propertyKeysArray, ref, variant;
miniCartItemsWrap = $(".mini-cart-items-wrap");
miniCartItemsWrap.empty();
if (cart.item_count !== 1) {
itemText = Theme.cartItemsOther;
} else {
itemText = Theme.cartItemsOne;
$(".mini-cart .options").show();
miniCartItemsWrap.find(".no-items").hide();
}
$(".mini-cart-wrap label").html("<span class='item-count'>" + cart.item_count + "</span> " + itemText);
ref = cart.items;
for (j = 0, len = ref.length; j < len; j++) {
item = ref[j];
productPrice = Shopify.formatMoney(item.line_price, Theme.moneyFormat);
variant = item.variant_title ? "<p class='variant'>" + item.variant_title + "</p>" : "";
itemProperties = "";
if (item.properties) {
propertyKeysArray = Object.keys(item.properties);
propertiesArray = _.values(item.properties);
i = 0;
while (i < propertyKeysArray.length) {
if (propertiesArray[i].length) {
itemProperties = itemProperties + ("<p class=\"property\">\n <span class=\"property-label\">" + propertyKeysArray[i] + ":</span>\n <span class=\"property-value\">" + propertiesArray[i] + "</span>\n</p>");
}
i++;
}
}
miniCartItemsWrap.append("<div id=\"item-" + item.variant_id + "\" class=\"item clearfix\">\n <div class=\"image-wrap\">\n <img alt=\"" + item.title + "\" src=\"" + item.image + "\">\n <a class=\"overlay\" href=\"" + item.url + "\"></a>\n </div>\n <div class=\"details\">\n <p class=\"brand\">" + item.vendor + "</p>\n <p class=\"title\">" + item.product_title + "<span class=\"quantity\">× <span class=\"count\">" + item.quantity + "</span></span></p>\n <p class=\"price\"><span class=\"money\">" + productPrice + "</span></p>\n " + variant + "\n " + itemProperties + "\n </div>\n</div>");
}
if (Theme.currencySwitcher) {
return $(document.body).trigger("switch-currency");
}
};
Liquid uses array.size to determine the size of an array. That's why your header is working from your Liquid template.
JavaScript, on the other hand, uses array.length to determine the size of the array. Try replacing cart.items.size in your JavaScript with cart.items.length

Categories

Resources