How to update a separated element with axios? - javascript

My code right now works perfectly fine!
It updates the user status(disable, enable account) without refreshing the page.
Right now if I click to the red button Desactiver it will become green Activer and the same thing in reverse..
What I wanna do is: When I Click to the button the status also get updated (which is in a different <td> )
In my axios code, I tried to get the status element using
const statusText= this.querySelector('span.status11');
and update it using
statusText.textContent=response.data.current;
The problem is that using this.querySelector return null because it is in a different <td>
and this points to a.js-status because on my code i did
document.querySelectorAll('a.js-status').forEach(function(link)
Here is the image
Here is my current code that updates ONLY the button (while i wanna update the button + the status <td>
Controller function:
/**
* #Route("/{id}/status", name="user_status", methods={"GET","POST"})
* #param Request $request
* #param User $user
* #return Response
*/
public function updateStatus(User $user): Response
{
if($user->getStatus()==true){
$user->setStatus(false);
$current="Desactiver";
} else {
$user->setStatus(true);
$current="Activer";
}
$this->getDoctrine()->getManager()->flush();
return $this->json([
'code'=>200,
'message'=>'the Status of is updated',
'current'=>$current
],200);
}
html code :
{% if user.status == 0 %}
Compte est <span class="status11" >Desactiver</span>
{% else %}
Compte est <span class="status11" >Activer</span>
{% endif %}
</td>
<td>
{% if user.status == 1 %}
<button class="btn btn-danger btn-sm">Desactiver</button>
{% else %}
<button class="btn btn-success btn-sm">Activer</button>
{% endif %}
</td>
My axios/javascript code :
{% block javascripts %}
<script src="https://unpkg.com/axios/dist/axios.min.js"> </script>
<script>
function onClickBtnLike(event){
event.preventDefault();
const url = this.href;
const btn= this.querySelector('button');
axios.get(url).then(function(response){
if(btn.classList.contains('btn-danger')) {
btn.classList.replace('btn-danger','btn-success');
btn.textContent="Activer";
}else{
btn.classList.replace('btn-success','btn-danger');
btn.textContent="Desactiver";
}
});
}
document.querySelectorAll('a.js-status').forEach(function(link){
link.addEventListener('click',onClickBtnLike);
})
</script>
{% endblock %}

You can traverse up from the button to the containing row and search for your status span from there:
const status = this.closest('tr').querySelector('.status11');
status.textContent = (status.textContent == "Activer" ? "Desactiver" : "Activer");
You could also target the previous td directly by using this.parentElement.previousElementSibling but the former is clearer and gives you some leeway if you want to change the html structure.

Related

Using Javascript to change text Content of a button

Hey guys I'm creating a social media messaging app and right now I'm on the basics of creating a button to follow people.
When you click the button, it should change the button from saying "Follow" to "UnFollow". Then the counter for Followers should go up by 1.
So far this is my code and it's not doing anything. I'm not getting any errors but it's also not doing anything at all.
Can someone figure out what I'm doing wrong? Thanks
network.js:
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('followButton').addEventListener('click', () => follow_user());
});
function follow_user() {
const element = document.getElementById('followButton');
element.value = "Un-Follow";
const element2 = document.getElementById('followers');
element2.textContent += 1;
}
profile.html :
{% extends "network/layout.html" %}
{% block body %}
<h2>{{user.username}}'s Profile</h2>
<p id="followers">Followers: {{user.followers}}</p>
<p>Follows: {{user.follows}}</p>
{% for newquery in newqueries reversed %}
<div class="newpost"><p>{{ newquery.body }}</p><p>By: {{ newquery.username }} on: {{ newquery.timestamp }} Likes: {{ newquery.likes }}</p></div>
{% endfor %}
<input type="button" value="Follow" id="followButton">
{% endblock %}
Your first problem is your follower count does not have an ID. You are trying to target it with #followers, but it only has a class .followers.
Your second problem is button inputs don't display textContent. They display their value.
const element = document.getElementById('followButton');
element.value = "Un-Follow";
Try something like this: const element = document.getElementById("followButton").value="Un-Button Follow" i think the value should be Button in between the un and follow i.e un-follow, Note(change it to suit your code)
Check this article here: https://www.permadi.com/tutorial/jsInnerHTMLDOM/index.html

Can't process ajax call on my page because Django request.is_ajax returns True when page is intially loaded

I have a page that makes ajax calls, and my view checks if the call is ajax with .is_ajax function. However, when the page is initially loaded (for example if I stop running the server and then restart it) the is_ajax function seems to return True, which causes a MultiValueDictKeyError at /alltext, because the request does not contain the key "alltext", which contains the data from my other ajax call.
The page is a e-commerce product page, and the product has different variants (i.e. size and color), and when the user chooses variants from a dropdown menu (i.e. Large, Blue), it makes an ajax call to the backend to retrieve the price of this specific variant from the database.
Here is my code:
views.py
def product_info(request):
if request.method == "GET" and not request.is_ajax: # this is supposed to be loaded on page load
return render(request, "product_info.html")
elif request.is_ajax and request.method == "GET":
print(request.is_ajax)
'''When a user chooses a product variant on the page, this makes an ajax call
to retrieve the price of this combination'''
print("request was ajax")
combinations = request.GET["alltext"]
combinations_list = combinations.split(";")
product = Product.objects.all().latest("id")
var_names = Variation.objects.filter(product=product)
corresponding_values = []
for i in range(len(combinations_list)):
# finding this variant in database
var_name = var_names[i]
var_values = VariationValue.objects.filter(variation_name=var_name)
for val_obj in var_values:
val = val_obj.value
if val == combinations_list[i]:
corresponding_values.append(val_obj)
found_price = None
for i in range(len(corresponding_values)):
val = corresponding_values[i]
if i == 0:
combo_query = VariationCombination.objects.filter(variation_value=val)
else:
combo_query = combo_query.filter(variation_value=val)
price = combo_query[0].price
return HttpResponse("You chose: " + combinations + "price: " + price)
And here is the relevant part of the product_info page - the forms where the user chooses the variants and the script that sends the variants to the backend:
product_info.html
<form class="variations-form">
{% for name in variation_names %}
<div class="form-group">
<label class="btn-label">{{ name.variation_name }}:</label>
<!--<button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown">
<span class="selection"></span><span class="caret"></span>
</button>-->
<select name="variation{{ forloop.counter }}" class="form-control variations" id="variation{{ forloop.counter }}">
<option value="" selected disabled>{{ name.variation_name }}</option>
{% for key, value_list in variation_values.items %}
{% if key == name.variation_name %}
{% for value in value_list %}
<option value="{{ value }}">{{ value }}</option>
{% endfor %}
{% endif %}
{% endfor %}
</select>
</div>
<br>
{% endfor %}
</form>
Script tag with ajax call
<script>
$(document).ready(function () {
$('.form-control').change(function(){
if ($('#variation1').val()) {
var valueFrom = $('.variations option:selected').map(function () {
return $(this).val();
}).get();
var alltext = valueFrom.join(";")
$('#chosen-options').html(alltext).show('fast');
$.ajax(
{
type:"GET",
data:{
'action':'options_chosen',
alltext: alltext
},
success: function( data )
{
$('#chosen-options').html(data).show('fast');
}
});
};
});
});
</script>
Still not entirely sure what was wrong but I fixed it! At first, the page was setup so that it loads the template "homepage.html" at first, and then when you click on a product it opens in the same page, by loading the template "product_info.html". So I just changed it so that the product_info opens up on a new page when you click a product (and added the new page to urls.py), and now it works!

How to hide Django form fields using JavaScript, Jquery etc

I would like to dynamically
hide form fields. The user should be able to select the component type, which could be a VALVE in which case the user should specify the Kv value and the DI and length fields should be hidden. Or the user could select the PIPE component type in which case the user should specify the inner diameter (DI) and length of the pipe and the k_v field should be hidden.
The model is defined as follows:
class Component(models.Model):
COMPONENT_TYPE_CHOICES = (
(1, 'k_v'),
(2, 'pipe')
)
circuit = models.ForeignKey('circuit.Circuit', related_name='components', on_delete=models.CASCADE)
component_type = models.IntegerField(default=1, choices = COMPONENT_TYPE_CHOICES)
component_name = models.CharField(max_length=200)
branch_number_collectors = models.IntegerField(default=4)
# Hide if component_type==2
k_v = models.FloatField(default=1)
# Hide if component_type==1
DI = models.FloatField(default=0.025)
length = models.FloatField(default=1)
# Calculated properties
branch_volumetric_flow_rate = models.FloatField(default=0)
branch_mass_flow_rate = models.FloatField(default=0)
velocity = models.FloatField(default=0)
reynolds = models.FloatField(default=0)
friction_coefficient = models.FloatField(default=0)
pressure_loss = models.FloatField(default=0)
#classmethod
def create( cls,
circuit,
...,
The forms.py is as follows:
class ComponentForm(forms.ModelForm):
class Meta:
model = Component
fields = [
'component_type',
'component_name',
'branch_number_collectors',
'k_v',
'DI',
'length'
]
The simplified Django template is as follows:
{% block content %}
<form method='POST'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Save</button>
</form>
{% endblock %}
first go to django shell and then do the following:
python manage.py shell
from yourapp.yourform import ComponentForm
f = ComponentForm()
print(f.as_p())
this will give you all the id and class names you can use in your javascript or CSS to manipulate.
lets say you want to hide length then you will do:
$(document).ready(function(){
$('#id_length').hide();
})
Ok I solved the problem. When the user selects the PIPE option form the component_type dropdownlist the k_v field is hidden and the DI and length fields are shown. When the user selects the k_v option from the component_type dropdownlist the k_v field is shown and the length and DI fields are hidden.
My Django template is now as follows:
{% extends 'base.html' %}
<script>
{% block jquery %}
// Call hideShow when page is loaded
$(document).ready(function(){
hideShow()
})
// call hideShow when the user clicks on the component_type dropdownlist
$('#id_component_type').click(function(){
hideShow()
});
// The jquery function below hides/shows the k_v, DI and length fields depending on the selected component_type
function hideShow(){
if(document.getElementById('id_component_type').options[document.getElementById('id_component_type').selectedIndex].value == "1")
{
$('#id_length').parents('p:first').hide();
$('#id_DI').parents('p:first').hide();
$('#id_k_v').parents('p:first').show();
}else
{
$('#id_length').parents('p:first').show();
$('#id_DI').parents('p:first').show();
$('#id_k_v').parents('p:first').hide();
}
}
{% endblock %}
</script>
{% block content %}
<form method='POST'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Save</button>
</form>
{% endblock %}

Shopify run for loop again after clicking Check-Out button

I'd like to run this for-loop again after clicking the checkout button, to check if the quantity is 2 oder less to set check_nike = true.
is this possible without reloading the side again after the customer set the product quantity on 2?
{% for item in cart.items %}
{% if item.title contains 'nike' %}
{% if item.quantity > 2 %}
{% assign check_nike = false %}
{% endif %}
{% endif %}
{% endfor %}
I have although implemented this in my theme.liquid
$('body').on('click', '[name="checkout"], [name="goto_pp"], [name="goto_gc"]', function() {
if ($('#agree').is(':checked') && {{check_nike}} == true ) {
$(this).submit();
}
else {
if({{check_nike}} == false){
alert("You can't only order two Nike products");
}
else{
document.getElementById("centerbox1").className += " forgottocheck";
}
return false;
}
});
</script>
Thanks :)
You can't use liquid code {{ check_nike }} in a JavaScript for any client side activity. Rather you can try checking the cart.js file of Shopify.
Whenever a product is added to cart use GET as shown in - https://docs.shopify.com/themes/development/getting-started/using-ajax-api#get-cart to see if you specific condition matches.
Going further you can also use localStorage or cookies to reduce the number of GET calls by storing specific cart information locally.

How to change model variable by onclick function used in template asynchronously (without refreshing explicitly)

I am making a django app where the user can post status'. The list of his previous status' is also showed on the same page with a delete post option against each post. I have added an onclick function to that button which uses ajax calls to change the class variable in models.py. ie. the delete variable in class status_class in models.py changes its value from 0 to 1 after the delete post button is clicked. And then only the posts with delete=1 are showed. Help me modify the delete_post function in the script so that it works as I've mentioned above. Please do mention if any other changes are needed. Thanks.
Models.py
from django.db import models
from django.contrib.auth.models import User
class status_class(models.Model):
username=models.ForeignKey(User)
text=models.CharField(max_length=2000, null=False, blank=False)
pub_date=models.DateTimeField("Published: ")
delete=models.IntegerField(default=0)
def __unicode__(self):
return self.text
Script in template
<script>
function deletepost(id)
{
$.ajax({
url: "/delete_post/",
type: "POST",
data: {'value':id},
success: function(response) {
},
});
}
</script>
URL
url(r'^delete_post/$', 'status.views.deletepost_view', name='deletepost_view'),
View
#csrf_exempt
def deletepost_view(request):
value=request.POST.get("value")
b=User.objects.filter(id=str(value))
#delete change statement
resp=json.dumps(b)
return HttpResponse(resp, content_type="application/json")
Template
{% for i in d %}
<p>{{ i.text }} &nbsp&nbsp&nbsp&nbsp {{ i.pub_date }}
<button type="button" class="btn btn-danger" onclick="deletepost(i.id);"> Delete Post </button></p>
<hr>
{% endfor %}
NOTE: Also help me with this. I want to filter posts and show only that posts having the delete variable equal to 0. ie. that have not been deleted. Where should I write the filter statement?
The changes to the following would work.
View
def deletepost_view(request):
value=request.POST.get("value")
b=status_class.objects.get(id=str(value))
b.delete = 1
b.save()
resp=json.dumps(b)
return HttpResponse(resp, content_type="application/json")
Template
{% for i in d %}
<p>{% if i.delete == 0 %}
{{ i.text }}&nbsp&nbsp&nbsp&nbsp {{ i.pub_date }}
<button type="button" class="btn btn-danger" onclick="deletepost({{ i.id }});"> Delete Post </button>
<hr></p>
{% endif %}
{% endfor %}

Categories