1
\$\begingroup\$

I've just created a simple VAT calculator. The script works fine though some animations seem a little buggy. Being a javascript beginner I'd like to ask more experienced programmers their opinion about my code. Do you have any helpful criticism to make my code more performant?

document.addEventListener('DOMContentLoaded',function(){

//animation after DOM loaded
var all = document.querySelectorAll('p, h1, h4, input, button');
for(var i=0 ; i<all.length ; i++) {
	all[i].animate({
  			opacity: [ 0, 1 ],          
  			transform: [ 'translateY(50%)','translateY(0%)'  ]
			}, 1000);
};

//general variables
var btnNew = document.getElementById('newEntry');
var btnArray = [];
var btnList = document.getElementById('showListe');

var list = document.getElementById('liste');
var listHeight = list.getBoundingClientRect().height;
var startHeight = listHeight;

list.classList.add('hide');

var animer = document.querySelector('.animate');
var resultBlock = document.getElementById('resultats');


//details button (opne and close the list) + animations
btnList.addEventListener('click',function(){
	list.classList.toggle('animate-up');
	list.classList.toggle('animate-down');
	if (list.classList.contains('animate-down')){
		animer.animate({
  			opacity: [ 0, 1 ],          
  			transform: ['translateY(-100%)','translateY(0%)']
			}, 500);
		list.classList.toggle('hide');
		resultBlock.animate({
			transform: ['translateY('+-startHeight+'px)','translateY(0%)']
		}, 500);
	} else {
		animer.animate({
  			opacity: [ 1, 0 ],          
  			transform: ['translateY(0%)','translateY(-100%)'] 
			}, 500);
		setTimeout(function(){list.classList.toggle('hide')},500);
		var listHeight = list.getBoundingClientRect().height;
		resultBlock.animate({
			transform: ['translateY(0%)','translateY('+-listHeight+'px)']
		}, 500);
		
	};
});

function countTotal() { 
	//calculate sums then display them in the DOM
	var arrayHT = document.querySelectorAll('#addHT');
	var countHT = 0;
	for (var i=0 ; i<arrayHT.length ; i++) {
		countHT+=parseFloat(arrayHT[i].innerHTML);
	};

	var arrayTTC = document.querySelectorAll('#addTTC');
	var countTTC = 0;
	for (var i=0 ; i<arrayTTC.length ; i++) {
		countTTC+=parseFloat(arrayTTC[i].innerHTML);
	};

	document.getElementById('totalHT').value = Math.round(countHT*100)/100;
	document.getElementById('totalTTC').value =Math.round(countTTC*100)/100;
};

//reinitialise input fields to default value
function reinitialiseInput() {
	document.getElementById('nom').value ='';
	document.getElementById('qte').value ='';
	document.getElementById('prix').value ='';
};

//calculate and add new entry to DOM
btnNew.addEventListener('click', function(){
	
	//create basic values
	var VATrate = document.getElementById('txTVA').value;
	var entryName = document.getElementById('nom').value;
	var quantity = document.getElementById('qte').value;
	var price = document.getElementById('prix').value;
	var sumHT = price*quantity;
	var VAT = (VATrate/100)*sumHT;
	var sumTTC = sumHT+VAT;
	
	//create html elements and assign them a value
	var elementName = document.createElement('p');
	elementName.innerHTML = entryName;
	var elementUnitPrice = document.createElement('p');
	elementUnitPrice.innerHTML= price;
	var elementQuantity = document.createElement('p');
	elementQuantity.innerHTML = quantity;
	var elementVATrate = document.createElement('p');
	elementVATrate.innerHTML = VATrate+'%';
	var elementVAT = document.createElement('p');
	elementVAT.innerHTML = VAT.toFixed(2);

	var elementSumHT = document.createElement('p');
	elementSumHT.innerHTML = sumHT;
	elementSumHT.id ="addHT";

	var elementSumTTC = document.createElement('p');
	elementSumTTC.innerHTML = sumTTC;
	elementSumTTC.id ="addTTC";

	var btnDelete = document.createElement('button');
	btnDelete.innerHTML = 'Effacer';
	btnDelete.classList.add('btn', 'btn-danger');
	btnDelete.id = "deleteBtn";

	var newRow = document.createElement('div');
	newRow.classList.add('row', 'list-row');
	
	//put all elements in array
	var elementArray = [elementName,elementUnitPrice,elementQuantity,elementVATrate,elementVAT,elementSumHT,elementSumTTC,btnDelete];
	
	//loop this array to add a class to each element, then add them into a row
	for (var i=0 ; i<elementArray.length ; i++) {
		elementArray[i].classList.add('list-element');
		newRow.appendChild(elementArray[i]);
	};

	//add new row to the list
	list.appendChild(newRow);

	//animation when adding a new row with list openned
	var rowHeight = newRow.getBoundingClientRect().height;
	if (list.classList.contains('animate-down')){
		newRow.animate({
  			opacity: [ 0, 1 ],          
  			transform: [ 'translateY(-100%)','translateY(0%)'  ]
			}, 500);
		resultBlock.animate({
			transform: ['translateY('+-rowHeight+'px)','translateY(0%)']
		}, 500);
	} ;
	
	//reinitialise inputs and calculate sums
	reinitialiseInput()
	countTotal();

	//delete row + animation
	btnArray.push(btnDelete);
	(function(){
		btnArray[btnArray.length-1].addEventListener('click',function(){
			var thisRow = this.parentNode;
			var thisRowHeight = thisRow.getBoundingClientRect().height;
			thisRow.animate({
	  			opacity: [ 1, 0 ],          
	  			transform: [ 'translateY(0%)','translateY(-100%)'  ]
				}, 500);
			setTimeout(function(){
				thisRow.parentNode.removeChild(thisRow);
			},500);
			resultBlock.animate({
			transform: ['translateY(0%)','translateY('+(-thisRowHeight)*0.75+'px)']
			}, 500);
			setTimeout(function(){
				countTotal();
			},500);	
		});
	}());
});
});
.container{
	display: flex;
	flex-flow: column nowrap;
}

.section {
	margin-top: 0.5em;
	margin-bottom: 0.5em;
}

.section:not(.section1):not(.section4){
	display:flex;
	flex-flow: row nowrap;
}

.section2 {align-items: baseline;}

.section3 {
	justify-content: space-between; 
	align-items: flex-end;
}

.section3 div {flex-grow: 1;}
.section3 button {flex-grow: 6;}
.section4 {flex-flow: column nowrap;}

.section5, .section6 {justify-content: flex-end;}

.section1, .section2, .section4 {justify-content: flex-start;}

input{
	border: 1px solid #d3d3d3;
	text-align: right;
}

.list-container {
	overflow: hidden;
}

.list-row{
	display: flex;
	flex-flow: row nowrap;
	margin-bottom: 0.5em;
	overflow: hidden;
}

.list-element {
	width:12.5%;
}

.hide {
	display: none;
}
	
<!DOCTYPE html>
<html>
<head>
	<title>Cacul TVA</title>
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
	<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
	<div class="container">

		<div class="row">
			<div class="col-md-6 section section1">
				<h1>Calcul de TVA</h1>
				<p>Entrez vos dépenses hors-taxe ci-dessous afin d'obtenir le total HT et le total TTC.</p>
			</div>
		</div>
		<div class="row">
			<div class="col-md-8 section section2">
				<p>Taux de TVA:</p>
				<input type="number" value="20" id="txTVA">
				<p>%</p>	
			</div>
		</div>
		<div class="row">
			<div class="col-md-8 section section3">
				<div class="input_block">
					<p>Nom</p>
					<input type="text" id="nom">
				</div>
				<div class="input_block">
					<p>Quantité</p>
					<input type="number" id="qte">
				</div>
				<div class="input_block">
					<p>Prix</p>
					<input type="number" id="prix">
				</div>
				<button class="btn btn-primary" id="newEntry">Entrée</button>
			</div>
		</div>
		<div class="row ">
			<div class="col-md-8 section section4">
				<h4 id="showListe">Détails<span class="caret"></span></h4>
			</div>
		</div>
		<div class="row list-container">
			<div class="col-md-8 section section4 animate animate-up" id="liste">
				<div class="row list-row">
					<h5 class="list-element">Nom</h5>
					<h5 class="list-element">Prix Unitaire</h5>
					<h5 class="list-element">Quantité</h5>
					<h5 class="list-element">Taux TVA</h5>
					<h5 class="list-element">TVA</h5>
					<h5 class="list-element">Somme HT</h5>
					<h5 class="list-element">Somme TTC</h5>
					<h5></h5>
				</div>
				<hr>			
			</div>
		</div>
		<div id="resultats">	
			<div class="row">
				<div class="col-md-8 section section5">
					<h4>Total HT:</h4>
					<input type="number" name="" placeholder="0" id="totalHT" readonly="true">
				</div>
			</div>
			<div class="row">
				<div class="col-md-8 section section6">
					<h4>Total TTC:</h4>
					<input type="number" name="" placeholder="0" id="totalTTC" readonly="true">
				</div>
			</div>
			<hr>
		</div>
	</div>
	
	<script type="text/javascript" src="script.js"></script>
</body>
</html>

\$\endgroup\$
  • 3
    \$\begingroup\$ Oh là là, too bad that most people here don't speak French and therefore cannot understand your variable names. \$\endgroup\$ – Roland Illig Sep 15 '17 at 13:27
  • 3
    \$\begingroup\$ Indeed, I second what Roland said. English is not my native language, but even when I'm writing code just for fun, for me alone, I name all the variables and functions with English names. It's a good habit, that should become second nature and, of course, applied to your professional codes. That way, when a problem shows up (like now), you'll get help faster. \$\endgroup\$ – Gerardo Furtado Sep 15 '17 at 14:09
  • \$\begingroup\$ Code with foreign language identifiers is perfectly acceptable on Code Review. Please do not translate code just for the sake of asking for a review. \$\endgroup\$ – 200_success Sep 15 '17 at 15:08
  • \$\begingroup\$ some (more) english comments at least would be nice \$\endgroup\$ – I wrestled a bear once. Sep 15 '17 at 18:18
  • 1
    \$\begingroup\$ For Nom, Quantité and Prix equal 0,99, and Taux de TVA equal 12%, result is 1,1088 and as such Total TTC should read 1,11, while it reads 1,10. When talking money and such, always operate on cents (more generally, smallest indivisible unit). Flaws like that has been used in the past to steal relatively large amounts. \$\endgroup\$ – Przemek Sep 16 '17 at 18:18
2
\$\begingroup\$

A lot of your code is concerned with handling the animations. There are a number of ways to get animations with less work (and code) involved.

bootstrap collapse

Since you're already using bootstrap, an easy way to show/hide the Details section might be to use a bootstrap collapse.

CSS3 transitions

If you need more control over the animations (and what you animate) and if you can use CSS3 in your project, you might want to consider using CSS3 transitions for animating the collapsible content.

$('#toggle').click(function() {
  $('#the-list').toggleClass('collapsed');
});
ul {
  transition: all 0.5s ease-in-out;
  max-height: 100vh;
}

ul.collapsed {
  max-height: 0;
  opacity: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<button id="toggle">toggle list</button>

<ul id="the-list" class="collapsed">
  <li>This is a list item</li>
  <li>This is a list item</li>
  <li>This is a list item</li>
  <li>This is a list item</li>
  <li>This is a list item</li>
</ul>

<p>some more content here</p>

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.