Using Javascript to change text Content of a button - javascript

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

Related

How I can use one js code of a django template for different content

I am working on a web application using Django I have faced one problem in that and that's I wrote one html template in Django and in that template I also has been written the code of js for that template. I want to use that js code for all the different kinds of content that is represented using that template in the front of the user.but that js code is not working for all kinds of content similarly.
Problem in brief
I am making a commerical web application for a Project like amazon.in and flipkart.com and I have writen a template for a product view page for all kinds of Product that is shown using that template. I has been made a button in that product view page template. Button is Add to Cart and I have written JavaScript code in that template for add to Cart button to store the product in the cart when the user click the button. I made my cart using LocalStorage and i will store the products in it.
but the problem is when I initialzed my site and click on the product and goes to the product view page and click to the Add to Cart and after click on it the js code will be executed successfully!! and the product will be stored in localStorage of the browser. but When I goes back to the Products list page and click on the another Product and goes to its Product view page and then I click the Add to Cart Button it will do nothing and show some kind of error which is about Uncaught Type Error and the product is not listed in the cart. but when I clear my cart (localStorage) by using localStorage.clear() and when it is empty the product is listed in the localStorage after clicking on the Add to Cart Button.
and when one Product is listed in it. it show same error again for other one. so How I can solve it and gets my desired result.
if you know that how it will be solved so please share with and help me out and please let know also what kind of mistake i am doing in that.
My product view template code is here with js code embaded
{% extends 'MenuCategory/Navigation_bar.html' %}
{% block title %} {{Category.Item_Category}} {% endblock %}
{% block style %}
{% endblock %}
{% block head %}
{% endblock %}
{% block body %}
<div class="container-fluid mt-3">
<div class="list-group">
{% for item in Content %}
<a href="#" class="list-group-item list-group-item-action" aria-current="true">
<div class="row">
<div class="col-1 d-flex align-items-center">
<img src="/media/{{item.Item_Image}}" class="rounded img-fluid" width="150px" height="150px">
</div>
<div class="col-8">
<div class="d-flex w-100 row">
<h5 id="nameby{{Category.Item_Category}}Product{{item.Item_ID}}" class="mb-1">{{item.Item_Name}}</h5>
<div class="d-flex w-100 row">
<p class="mb-1">{{item.Item_Description}}</p>
</div>
<div class="d-flex w-100 row">
<small id="PriceOf{{Category.Item_Category}}Product{{item.Item_ID}}">{{item.Item_Price}}</small>
</div>
</div>
</div>
<div class=" col-3 d-flex justify-content-end align-items-center mr-2">
<span id="btnspan{{Category.Item_Category}}Product{{item.Item_ID}}" class="AddBtn">
<button id="{{Category.Item_Category}}Product{{item.Item_ID}}" class="btn btn-primary {{Category.Item_Category}}CartButton">Add to Cart</button>
</span>
</div>
</div>
</a>
{% endfor %}
</div>
</div>
{% endblock %}
{% block script %}
document.getElementById("NavbarMainHeading").innerHTML="{{Category.Item_Category}}";
function updateCart(Cart) {
for (let item in Cart) {
console.log(item)
document.getElementById('btnspan' + item).innerHTML = `<button id="minus${item}" class="btn btn-primary minus">-</button><span id="val${item}">${Cart[item][0]}</span><button id="plus${item}" class="btn btn-primary plus">+</button>`
}
localStorage.setItem('Cart', JSON.stringify(Cart))
console.log(localStorage.getItem('Cart'))
}
if (localStorage.getItem('Cart') == null) {
var Cart = {};
} else {
Cart = JSON.parse(localStorage.getItem('Cart'))
updateCart(Cart)
}
let btns = document.getElementsByClassName('{{Category.Item_Category}}CartButton');
btns = Array.from(btns);
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function() {
var idstr = this.id.toString();
if (Cart[idstr] != undefined) {
Cart[idstr][0] = Cart[idstr][0] + 1;
} else {
name = document.getElementById("nameby" + idstr).innerHTML;
price = document.getElementById("PriceOf" + idstr).innerHTML;
quantity = 1;
Cart[idstr] = [quantity, name, parseInt(price)];
}
updateCart(Cart)
})
}
{% endblock %}
My urls.py code is here
from django.urls import path,include
from . import views
urlpatterns = [
# path('admin/', admin.site.urls),
path('',views.CategoryPage,name='MenuCategoryPage'),
path('Category/<str:Variety_Name>',views.Category_Items,name='CategoryItems')
My views.py of Django code is here
from django.shortcuts import render
from django.http import HttpResponse
from .models import Varieties,CategoryItems
def Category_Items(request,Variety_Name):
print(f"variety name {Variety_Name}")
post=CategoryItems.objects.filter(Item_Category=Variety_Name)
Category=None
print(len(post))
if len(post) >= 1:
Category=post[0]
content={'Content':post,'Category':Category}
return render(request,'MenuCategory/Product_List.html',content)
My models.py code is here
from django.db import models
# Create your models here.
class Varieties(models.Model):
VarietyID=models.AutoField(primary_key=True)
Variety_Name=models.CharField(max_length=50,default='Variety name should be within 50 characters.')
Variety_Image=models.ImageField(default='')
def __str__(self):
return self.Variety_Name
class CategoryItems(models.Model):
Item_ID=models.AutoField(primary_key=True)
Item_Category=models.CharField(max_length=50,default="Variety Name and Category Name must be same.")
Item_SubCategory=models.CharField(max_length=50,default="SubCategory Name")
Item_Image=models.ImageField(default='')
Item_Name=models.CharField(max_length=50,default='Ex: Paneer Pratha')
Item_Price=models.IntegerField()
Item_Description=models.CharField(max_length=1000,default='Write Something about speciality of the Product.')
def __str__(self):
return f"{self.Item_Name} - {self.Item_Category}"
Error that occur in Console when I want to add an item in the cart when localStorage already have one item in it
But When localStorage is Empty the item is Stored in it Successfully
The Problem that I found in this code is that when we call updateCart function with Cart parameter which is an object. When we itreate it in the updateCart function by the using of for loop. At that time we took a variable called item in it as
for (let item in Cart) {
console.log(item)
document.getElementById('btnspan' + item).innerHTML = `<button id="minus${item}" class="btn btn-primary minus">-</button><span id="val${item}">${Cart[item][0]}</span><button id="plus${item}" class="btn btn-primary plus">+</button>`
}
So, in this item is the key name of the Cart object. when you see the for loop which is outer side of the function which has been used for the attachment of EventHandler for the buttons Add to Cart.
the for loop is :
let btns = document.getElementsByClassName('{{Category.Item_Category}}CartButton');
btns = Array.from(btns);
for (let i = 0; i < btns.length; i++) {
btns[i].addEventListener('click', function() {
var idstr = this.id.toString();
if (Cart[idstr] != undefined) {
Cart[idstr][0] = Cart[idstr][0] + 1;
} else {
name = document.getElementById("nameby" + idstr).innerHTML;
price = document.getElementById("PriceOf" + idstr).innerHTML;
quantity = 1;
Cart[idstr] = [quantity, name, parseInt(price)];
}
updateCart(Cart)
})
}
if you see this, you will notice that the variable idstr which is declared inside the for loop. It is used for storing the value of id of button which is clicked at a time.At the last inside the for loop in the else section fetch the details of item by the using of idstr variable and after that we will store these details in the Cart object as a array along with that object key name is idstr which is the id of the button that was clicked.Then we will pass Cart object as an argument to the function updateCart
So Every time When you Change the Content of the template the id of the button will also Change because the id of the button is {{Category.Item_Category}}Product{{item.Item_ID}} which is dynamically change for every new category page.
So we have to put one if statement in the for loop of updateCart function before of Changing the button "Add to Cart" to another one.
just like that:
function updateCart(Cart) {
for (let item in Cart) {
if("{{Category.Item_Category}}" == `${item}`.slice(0,"{{Category.Item_Category}}".length)){
document.getElementById('btnspan' + item).innerHTML = `<button id="minus${item}" class="btn btn-primary minus">-</button><span id="val${item}">${Cart[item][0]}</span><button id="plus${item}" class="btn btn-primary plus">+</button>`
}
}
localStorage.setItem('Cart', JSON.stringify(Cart))
console.log(localStorage.getItem('Cart'))
}
In the if statement which we add in the for loop we made a comparison of Categories name
As you see in the question that button id is containing the Category Name of the items and the items are also divided by the Category So for Every Category the Template page will be one with the same id of buttons and of other elements. So we made a Comparison between the Category Name of the item.
By the help of this Comparison the buttons are changed if the Category name are same from both side and rest of the elements/buttons are skiped automatically.
in this way there are no error are occur and code runs smoothly.
I hope this Answer will help you!!
Added If Statement are:
if("{{Category.Item_Category}}" == `${item}`.slice(0,"{{Category.Item_Category}}".length))

HTML Button is non-responsive, console doesn't register event

Working on a simple to-do app, but having a problem with the delete button. When I click, the browser console doesn't even register an event. Super confused on what to do here. I've gone through all my code in index.html as well as the app.py code, I can't figure out why it's not even registering in the browser that something happened, even if it doesn't lead to what I want it to do. Basically just not sure how to debug something that's not even registering as existing I guess?
I'm assuming it's a problem in the HTML but just in case, I'm including the relevant python code as well.
Thanks!
index.html
<ul id="todos">
{% for d in data %}
<li><input class="check-completed" data-id="{{ d.id }}"
type="checkbox" {% if d.completed %} checked {% endif %}> {{ d.description }}
<button class="li button deletebutton" data-id="{{ d.id }}">&cross;</button> <!-- &cross; is HTML for an X-->
</li>
{% endfor %}
</ul>
script in index.html:
const deletebtns = document.querySelectorAll('.deletebutton');
for (let i = 0; i < deletebtns.length; i++) {
const deletebutton = deletebtns[i];
deletebutton.onclick = function(e) {
const todoId = e.target.dataset['id'];
fetch('/todos/' + todoId, {
method: 'DELETE',
})
}
}
}
app.py:
#app.route('/todos/<todo_id>', methods=['DELETE'])
def delete_todo(todo_id):
try:
Todo.query.filter_by(id=todo_id).delete()
db.session.delete(todo)
db.session.commit()
except:
db.session.rollback()
finally:
db.session.close()
return redirect(url_for('index'))

How do you properly clone something in Javascript/JQuery?

I'm using .clone() to duplicate a form. I make small changes to the clone and then place it after the last form. As you can see from the screenshot it's mostly working; they look identical. The application (Django/Python) can process the clone as well once I press save.
The problem is the calendar widget does not open when clicked (on the clone form). It does open if I click on the widget button for a form that already exists on the page when it first loads (not a clone). But on my clones the date picker does not open.
What it should look like after I click on it (instead nothing happens):
The cloned html seems to look identical in all the right ways.
Existing form:
Clone:
EDIT Event Listeners:
Looking at the Event Listeners for the tag the on click event seems to me missing.
Existing Form:
Clone:
Is something missing from the cloned html? Or is there something behind the scenes that is not working? I just don't understand what is broken here.
JS/JQuery:
function cloneMore(selector, prefix,form_class) {
var newElement = $(selector).clone(true);
var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
newElement.find(':input:not([type=button]):not([type=submit]):not([type=reset])').each(function() {
var name = $(this).attr('name').replace('-' + (total-1) + '-', '-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
});
newElement.find('label').each(function() {
var forValue = $(this).attr('for');
if (forValue) {
forValue = forValue.replace('-' + (total-1) + '-', '-' + total + '-');
$(this).attr({'for': forValue});
}
});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
return false;
}
$(document).on('click', '.add-form-row', function(e){
e.preventDefault();
cloneMore('.form-row-payment:last', 'payment_invoice','form-row-payment');
return false;
});
HTML:
{{ payments_formset.management_form }}
{{ payments_formset.media }}
<h3>Payments</h3>
{% for formpay in payments_formset %}
<div class="form-row form-row-payment row container" name="payment_form" style="padding:0px;" id="payment_formset">
{{ formpay.non_form_errors }}
{{ formpay.non_field_errors }}
{% for hidden in formpay.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in formpay %}
{% if field.name != 'index' and field.name != 'invoice'%}
<div class="col-sm">
{{ field.errors }}
{{ field|as_crispy_field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endif %}
{% endfor %}
</div>
{% endfor %}
<div class="input-group-append">
<button class="btn btn-success add-form-row">+</button>
</div>
You are making a copy of the HTML objects, but these do not have the same event handlers as the original object. To remedy this, I would suggest making a function that will reset the event handlers for the cloned elements.
This could be done something like this:
function resetCalendarClickHandler(){
$(".input-group-addon").unbind("click") //remove current event handlers to prevent duplication when adding new one
$(".input-group-addon").click(<yourEventHandler>);
}
Once you have this, you can add a call to this function at the end of your cloneMore() function and this will re-assign the event handlers and include the cloned element as it will be part of your HTML at this point.

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 %}

Use a javascript array to display specific HTML divs

Using django I have a HTML page with a table containing checkboxes:
{% for o in obj %}
<input class='germ_ids' name='{{o.id}}'>
{% endfor %}
<script>
var elements = document.getElementsByClassName("germ_ids");
var ids = [];
for(var i=0; i<elements.length; i++) {
ids.push(elements[i].name);
}
</script>
This has given me an array of specific 'germ ids'. These relate to other django objects I have:
the same .html page:
{% for k, v in add_state_dict.items %}
<div class='{{k.id}}_statement'>
<p>{{v}}</p>
</div>
{% endfor %}
<div class='all_germ'>
<p>{{additional_statement}}</p>
</div>
What I want to achieve is a statement for each germ_id when their checkbox is checked. However when more than one boxes are checked, it makes a concat statement called additional_statement in the 'all_germ' class.
I have hard coded it in in a JSFiddle http://jsfiddle.net/sDsCM/1037/
However I want to use the elements in the array to do this to account for different array values.
You should not be using class names with IDs but instead use class names that categorize your checkboxes. As example I'll be using .checkbox-plus-info. Also, use a data attribute to find the associated statement (unless you can render them inside one div):
{% for o in obj %}
<input class='germ_ids checkbox-plus-info' name='{{o.id}}'
data-info-tag="info-{{o.id}}">
{% endfor %}
{% for k, v in add_state_dict.items %}
<div id='{{k.id}}_statement' class="info info-{{k.obj_id}}">
<p>{{v}}</p>
</div>
{% endfor %}
In the above, k of course needs to contain a reference to the object (its PK/ID). You should have that information in your view and add it to the context. You haven't posted your view/context code but the business logic should mostly be ready while you create the template context, so prepare as much as you can there.
In your JS:
$(".checkbox-plus-info").click(function() {
$(".info").hide(); // hide all
stmtElId = $(this).target.data("info-tag");
$("#" + stmtElId).show();
// check whether something has to be shown when several checkboxes are checked
// e.g. count whether all checkboxes are checked, or other logic
});

Categories