Javascript/jQuery problems

No problems :slight_smile:

Feel free to let me know if you have any questions, or would like anything else explained.

Every thing works great, and with less code. The only thing that didn’t quite worked was the way it didn’t allow the user to delete the first row. The way it was you could never delete the first row even if it wasn’t the only row, I resolved this by adding a variable that counts the numbers of rows and checks if it’s the only one or not.

Now it’s time to send it trough the DomPDF and format the invoice pdf for download. Thanks for the help, I’ll let you know if I ran into any trouble (most likely :slight_smile: )

Here’s the code:


$(document).ready(function(){

	//HTML row html template
	var numRows = 1;
	var template = $("#invoice-table > tbody > tr:first").clone();
		
	//Add row
	
	$(".add-row").on("click", function(e) {
		numRows++;
		var newRow = template.clone();
		$("#invoice-table > tbody > tr.row:last").after(newRow);
		e.preventDefault();
		
	});
	
	//Delete row
	
	$("#invoice-table").on("click",".delete-row", function(e) {
		
		var tableRow = $(this).closest("tr");
		

		if(numRows > 1){
			numRows--;
			tableRow.remove();
			updateTotal();
			
		} else {
			alert("You can't delete the only row!");
		}
		e.preventDefault();

	});
		
	//Calculate
	
	$("#invoice-table").on("input", function(e) {
	
		if(e.target.className !== "description") {
			updateTotal();
		}
					
	});
	
	//Update total function
	
	function updateTotal() {
		var subtotal = 0,

			iva = Number($(".iva").val()) / 100,
			irpf = Number($(".irpf").val()) / 100,
			totaliva,
			totalirpf;
			
		//Loop
		  $("#invoice-table > tbody > tr.row").each(function(){
          var quantity = $(this).find("input.cantidad").val(),
              cost = $(this).find("input.coste").val();
              price = +cost * +quantity;
          $(this).find("p.precio").text(price);
          subtotal += price;
        });
		
		totaliva = roundToTwo(subtotal*iva);
		totalirpf = roundToTwo(subtotal*irpf);
		total = subtotal + totaliva - totalirpf;
		
		
		
		$(".subtotal").text(subtotal);
		$(".totaliva").text(totaliva);
		$(".totalirpf").text(totalirpf);
		$(".total").text(roundToTwo(total));

	}
	
	
	//Round function
	function roundToTwo(value) {
        return(Math.round(value * 100) / 100);
      }

});


Thanks!

Hi,

I’m glad it’s working.

Just to be clear - you don’t need the $(document).ready(function(){ ... }); if you place your JS at the end of the page (ideally before the closing </body> tag).

Also, I had included code to prevent deletion of the last row.
Just use the :first-child filter, no need to count the rows :slight_smile:

$("#invoice-table").on("click",".delete-row", function(e) {
  var tableRow = $(this).closest("tr");
  if(tableRow.is(":first-child")){
    alert("Don't be silly!");
  } else {
    tableRow.remove();
    updateTotal();
  }
  e.preventDefault();
});

HTH

Hi, now that I have the javascript functioning I’ve added the domPDF and am trying to render the html to PDF. I have it working but the rows that I duplicate in the html don’t appear. I think I have to copy the html and put it into a variable so that the PHP can use it. Am I right? How would I be able to do that?

Here’s the current link: http://brunofelicio.com/staging/facturame/

Thanks a lot.

Hi,

I’m afraid I don’t quite understand your question.

You are using some PHP library to generate PDFs and you want to know how to use JS to send it a bunch of HTML (from which it should then render a PDF).

Is that correct?

Yes, I am using dompdf library to render the html output. I’ve managed to achieve an aceptable result. I’m just trying to render it better. Is dompdf the best option?

It seems like a good choice and the GitHub repo seems to be very active.
If you have acheieved a result that works for you, I would probably roll with it.

Hi, I now got one small problem. I copy the html table and send it trough the dompdf to generate the pdf, the problem is that when doing “$(“tbody”).html();” it doesn’t copy the input fields values that I change (example: changing the decription name or the quantity)…

Any ideas on how I could do this?

It doesn’t look like this is supported: https://github.com/dompdf/dompdf/issues/4

Saying that though, I don’t have any experience with dompdf, so maybe a workaround is out there.

If you can make me a minimal example of what isn’t working, I don’t mind investigating further.
(e.g. one form element that isn’t getting rendered and no other content).

Hi,
What I am doing is, I am using the POST in php to get the form values of the invoice, but I can’t get the ones in the description table bellow because I need to have somehow a loop that gathers how many lines I have, and then replicate that loop on the .php file that renders the pdf (don’t know if I am making myself clear… sorry).

So this is the index.php:


<!doctype html>

<head>
  <meta charset="utf-8">

  <!-- Always force latest IE rendering engine (even in intranet) & Chrome Frame
       Remove this if you use the .htaccess -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

  <title></title>
  <meta name="description" content="facturame">
  <meta name="author" content="">

  <!-- Mobile viewport optimized: j.mp/bplateviewport -->
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <!-- Place favicon.ico & apple-touch-icon.png in the root of your domain and delete these references -->
  <link rel="shortcut icon" href="/favicon.ico">
  <link rel="apple-touch-icon" href="/apple-touch-icon.png">


  <!-- CSS: implied media="all" -->
  <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600,700' rel='stylesheet' type='text/css'>
  <link rel="stylesheet" href="css/reset.css">
  <link rel="stylesheet" href="css/style.css">


  <!-- All JavaScript at the bottom, except for Modernizr which enables HTML5 elements & feature detects -->
  <!-- <script src="js/libs/modernizr-1.7.min.js"></script> -->

</head>

<body>

  <div id="container">
  <div id="page-container">
  
  <form id="invoice" method="POST" action="invoice_html.php"><!-- Invoice form -->
  <div id="main" role="main">
    <header>
		
		<h2>Factura</h2>
		
		<fieldset id="invoice-num">
			<input type="text" name="invoice" placeholder="Numero de factura" id="inv"/><br />
			<input type="text" name="date" placeholder="26-01-12"/><br />
		</fieldset>
    </header>
    
    	
    	<div id="adress">
    	
    		<fieldset id="from">
    		<h3>Factura de:</h3>
				<input type="text" name="name" placeholder="Escribe tu nombre"/><br />
				<input type="text" name="email" placeholder="Escribe tu email"/><br />
				<input type="text" name="tel" placeholder="Escribe tu teléfono"/><br />
				
			</fieldset>
		
			<fieldset id="billto">
			<h3>Facturar a:</h3>
				<input type="text" name="cname" placeholder="Escribe tu nombre"/><br />
				<input type="text" name="cemail" placeholder="Escribe tu e-mail"/><br />
				<input type="text" name="ctel" placeholder="Escribe tu telefono"/><br />
				
			</fieldset>
		
   		</div>	
   		
   		<div id="details">
   			
   				<table id="invoice-table">
   					
   					<thead>
   						<tr>
   							
   							<th class="description">Descripción</th>
   							<th>Cant.</th>
   							<th>Coste</th>
   							<th>Precio</th>
   							
   						</tr>
   					</thead>
   					<tbody>
   						
   						<tr class="row">
   							
   							<td class="article"><input class="description" type="text" name="description-value" placeholder="Descripción del articulo" size="40" value="ejemplo"/></td>
   							<td><input class="cantidad" type="text" name="cost" placeholder="Cant." size="2" value="0"/></td>
   							<td><input class="coste" type="text" name="qty" placeholder="Coste" size="2" value="0"/></td>
   							<td class="value"><span class="precio">0</span><input class="precio-hidden" type="hidden" name="price" value="0"></td>  
   							<td class="insert"><a class="delete-row" href="#">Delete Row</a></td>							
   						</tr>
   						
	   						
   						
   					</tbody>
   					<tfoot>
   						
   						<tr>
   							<td class="add"><a href="#" class="add-row">+ Add row</a></td>
   							<td colspan="2" class="bold">Subtotal</td>
   							<td class="subtotal">0</td>
   							<input class="subtotal-hidden" type="hidden" name="subtotal" value="0">
   						</tr>
   						<tr>
   						  <td class="noborder">&nbsp;</td>
   						  <td class="tax"></td>
   						  <td><span class="tax">IVA</span><input class="iva" type="text" name="tax1" placeholder="IVA" value="21" size="2"/></td>
   							<td class="totaliva">0</td>
   							<input class="totaliva-hidden" type="hidden" name="totaliva" value="0">
   						</tr>
   						<tr>
   						  <td class="noborder">&nbsp;</td>
   						  <td class="tax"></td>
   						  <td><span class="tax">IRPF</span><input class="irpf" type="text" name="tax2" placeholder="IRPF" value="21" size="2"/></td>
   							<td class="totalirpf">0</td>
   							<input class="totalirpf-hidden" type="hidden" name="totalirpf" value="0">
   						</tr>
   						<tr>
   						  <td class="noborder">&nbsp;</td>
   						  <td colspan="2" class="noborder"><strong>TOTAL</strong></td>
   							<td class="total">0</td>
   							<input class="total-hidden" type="hidden" name="total" value="0">
   							<input class="html-hidden" type="hidden" name="html" value="0">
   						</tr>
   					</tfoot>
   				</table>

   		
   		</div>
   		
   		<div id="pay">
   			<h3>Notas</h3>
   			<textarea name="notas"></textarea>
   		</div>

    	</div><!--! end of #main -->
 	
   
    </div> <!--! end of #page-container -->
    <div class="sidebar">
    		<input type="submit" name="submit" id="descargar" value="Descargar"/>
    		<input type="submit" name="Enviar" id="guardar" value="Guardar"/>
    	</div><!-- End of sidebar -->

   		</form>
   		<div class="clearfix"></div>
   <footer>
	<p>&#169; brunofelicio.com</p>		
  </footer>
  
  </div> <!--! end of #container -->
  
 

  <!-- JavaScript at the bottom for fast page loading -->

  <!-- Grab Google CDN's jQuery, with a protocol relative URL; fall back to local if necessary -->
  <script src="js/jquery-1.10.2.min.js"></script>
  <script src="js/app.js"></script>
  
  <script>
	
		 
  	$(function() {
    	$('#invoice').submit(function() {
    	
        row_html = $("tbody").html();
        
		$(".html-hidden").val(row_html);
        return true; // return false to cancel form action
    });
});
  </script>
  
  <!-- end scripts-->


  <!--[if lt IE 7 ]>
    <script src="js/libs/dd_belatedpng.js"></script>
    <script>DD_belatedPNG.fix("img, .png_bg"); // Fix any <img> or .png_bg bg-images. Also, please read goo.gl/mZiyb </script>
  <![endif]-->


  <!-- mathiasbynens.be/notes/async-analytics-snippet Change UA-XXXXX-X to be your site's ID -->
  <script>
    var _gaq=[["_setAccount","UA-XXXXX-X"],["_trackPageview"]];
    (function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.async=1;
    g.src=("https:"==location.protocol?"//ssl":"//www")+".google-analytics.com/ga.js";
    s.parentNode.insertBefore(g,s)}(document,"script"));
  </script>

</body>
</html>

This is the php the renders the PDF (it gets the variables from the previous php and puts it into the right places in the invoice template):


<?php 
	
	
	
	/* Company details */

	$factura = $_POST['invoice'];
	$fecha = $_POST['date'];

	$imagen = $_POST['image'];
	$nombre = $_POST['name'];
	$email = $_POST['email'];
	$tel = $_POST['tel'];
	$dir = $_POST['dir'];
	
	/* Client data */
	
	$cnombre = $_POST['cname'];
	$cemail = $_POST['cemail'];
	$ctel = $_POST['ctel'];
	$cdir = $_POST['cdir'];
	
	/* Invoice data */
	
	$description = $_POST['description-value'];
	$coste = $_POST['cost'];
	$cantidad = $_POST['qty'];
	$precio = $_POST['price'];
	
	
	$subtotal = $_POST['subtotal'];
	$impuesto1 = $_POST['totaliva'];
	$impuesto2 = $_POST['totalirpf'];
	$total = $_POST['total'];
	
	$notas = $_POST['notas'];
	
	$htmls = $_POST['html'];
	/* Call functions.php */
	
	require("functions.php");
	
	/* HTML Template */
	
	
	renderPDF('
		<html>
		<head>
		<style>
		
	
		
		
.clearfix {
  clear: both; }

body {
  font-family: "Open Sans", sans-serif;
  font-weight: normal;
  color: #404040;
  height: 100%;
  font-size: 14px; }

h1 {
  color: #171a1c;
  
  width: 500px; }
  h1 span {
    color: #171a1c;
    display: block; }

h3 {
  font-weight: normal;
  margin-top: 20px;
  margin-bottom: 20px;
  color: #171a1c; }

a {
  text-decoration: none; }
  a:hover {
    text-decoration: underline; }

/* TABLE */
table {
  position: relative;
  border-collapse: collapse;
  width: 100%; }
  table thead {
    border-bottom: 1px solid #959595; }
    
    table thead th {
      text-align: right;
      width: 13%;
      font-family: "Open Sans_semi", sans-serif;
      
      padding-right: 20px;
      padding-bottom: 18px; }
      
      table thead th:last-child {
        border-right: none; }
      table thead th.description {
        width: 60%;
        text-align: left; }
        
  table td {
    text-align: right;
   
    padding-right: 20px;
    vertical-align: middle; }
    
    table td.add {
      text-align: left; }
    table td span {
      display: inline-block;
      padding-bottom: 12px; }
  table input {
  	display:inline-block;
    text-align: right;
    
    width: 98%;
    padding-top: 0 !important;
    width: 80%; }
    
    table input.description {
      display:inline-block;
      text-align: left;
     
      width: 98%; }

/* RULES */
.bold {
  font-weight: 600; }

.iva, .irpf {
  width: 40% !important; }

.tax {
  color: #ccc;
  padding-right: 10px; 
  
  }

#container {
  width: 1000px;
  margin: 50px auto; }

a.add-row {
  color: #ccc;
  font-weight: 600; }
  a.add-row:hover {
    color: #2c79ec;
    text-decoration: none; }

#page-container {
  width: 800px;
  margin-bottom: 10px;}
 


#main {
  padding: 40px; }

header {
  overflow: hidden; }
  header img {
    }

header fieldset {
 
  width: 300px; }
  header fieldset input#inv {
    font-size: 18px; }

fieldset#invoice-num {
  text-align: right; 
 
  }
  fieldset#invoice-num input {
    text-align: right;
    width: 200px;
    padding-right: 0; 
    
    }
  fieldset#invoice-num input#inv {
    font-size: 21px; }

h2 {
  
  text-align: left;
  font-size: 32px;
  font-weight: 400; }

#adress {
  overflow: hidden;
  margin: 25px 0 100px;
  
   }

fieldset input {
  font-family: "Open Sans", sans-serif; }
  
fieldset#from {
  width: 340px;
 
  text-align: left !important;
  margin-right: 40px; 
  
  }
fieldset#billto {
  width: 340px;
  
  text-align: left !important;
 }

input[type="text"] {
  display: block;
  font-size: 14px;
  color: #666;
  
  appearance: none;
  -webkit-appearance: none;
  border: none;
 
  margin: 0px;
  box-sizing: border-box;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  width: 90% !important; }



textarea {
  padding: 20px;
  width: 93%;
  resize: vertical;
  border: none;
  
  font-family: "Open Sans", "Helvetica Neue", sans-serif;
  font-size: 14px;
 }

#pay {
  padding-bottom: 10px; }

#details {
  position: relative; }


.insert {
	background: red;
   }
  
.delete-row {
	display: none;
}

.total {
  font-size: 24px;
  font-weight: bold; }

#header {
	padding-bottom: 20px;
	
}
#header td, #adress-details td {
	
	text-align: left;
	vertical-align:text-top;
	
}
#header .inv-title{
	font-size: 32px;
	vertical-align:text-top;
}

#header .inv-number {
	text-align: right;
	
}
#header .inv-number span {
	color: #ccc;
	display: inline;
	line-height: 14px;
	font-family: "Open Sans_semi", sans-serif;
}
.row td {
	border-bottom: 1px solid #ccc;
}

</style>
		</head>
		<div id="main" role="main">
    
		<div id="header">
		<table width="100%" border="0" cellspacing="0" cellpadding="0">
			<tr>
				<td class="inv-title" width="50%">Factura</td>
				<td class="inv-number"><span>Numero: </span>'.$factura.'<br />
				<span>Fecha: </span>'.$fecha.'
				</td>
			</tr>
			
		</table>    
	</div>
    	
    	<div id="adress">
    	
    		<table id="adress-details" width="100%" border="0" cellspacing="0" cellpadding="0">
			  <tr>
			    <td width="50%">Factura de:</td>
			    <td width="50%">Factura para:</td>
			  </tr>
			  <tr>
			    <td>'.$nombre.'</td>
			    <td>'.$cnombre.'</td>
			  </tr>
			  <tr>
			    <td>'.$email.'</td>
			    <td>'.$cemail.'</td>
			  </tr>
			  <tr>
			    <td>'.$tel.'</td>
			    <td>'.$ctel.'</td>
			  </tr>
			</table>
		
   		</div>	
   		
   		<div id="details">
   			
   				<table id="invoice-table">
   					
   					<thead>
   						<tr>
   							
   							<th class="description">Descripción</th>
   							<th>Cant.</th>
   							<th>Coste</th>
   							<th>Precio</th>
   							
   						</tr>
   					</thead>
   					<tbody>'.$htmls.'</tbody>
   					
   					
   					<tfoot>
   						
   						<tr>
   							<td height="40px"></td>
   							<td colspan="2" class="bold">Subtotal</td>
   							<td class="subtotal">'.$subtotal.'</td>
   						</tr>
   						<tr>
   						  <td class="noborder">&nbsp;</td>
   						  <td class="tax">IVA</td>
   						  <td><span class="tax"></span><input class="iva" type="text" name="tax1" placeholder="IVA" value="21" size="2"/></td>
   							<td>'.$impuesto1.'</td>
   						</tr>
   						<tr>
   						  <td class="noborder">&nbsp;</td>
   						  <td class="tax">IRPF</td>
   						  <td><span class="tax"></span><input class="irpf" type="text" name="tax2" placeholder="IRPF" value="-21" size="2"/></td>
   							<td>'.$impuesto2.'</td>
   						</tr>
   						<tr>
   						  <td class="noborder">&nbsp;</td>
   						  <td colspan="2" class="noborder"><strong>TOTAL</strong></td>
   							<td class="total">'.$total.'</td>
   						</tr>
   					</tfoot>
   					
   				</table>

   		
   		</div>
   		
   		<div id="pay">
   			<h3>Notas</h3>
   			<p>'.$notas.'</p>
   		</div>

    	</div>
		</html>
	');
	

?>

This is the functions.php (that calls the DOM):


<?php 

$items = array();

function sendData($valor){

		

		foreach($valor as $item){

			$items[] = $item;
			
		}
		
		
	}




function renderPDF($content_var){

	if(isset($_POST['submit']))
	{
		$title = $_POST['invoice'];
		$content = $content_var;
		if(empty($content))
		{
			$error = "No fue posible renderizar el PDF!";
		}
		
		else {
		
			include_once('dompdf/dompdf_config.inc.php');
			
				
			$dompdf = new DOMPDF();
			$dompdf->load_html(utf8_decode($content));
			$dompdf->render();
			$dompdf->stream($title . '.pdf');
		
		}
	}
}

?>

And this is the js that you helped me with (works flawless):


$(document).ready(function(){

	//HTML row html template
	var numRows = 1;
	var template = $("#invoice-table > tbody > tr:first").clone();
		
	//Add row
	
	$(".add-row").on("click", function(e) {
		numRows++;
		var newRow = template.clone();
		$("#invoice-table > tbody > tr.row:last").after(newRow);
		e.preventDefault();
		
	});
	
	//Delete row
	
	$("#invoice-table").on("click",".delete-row", function(e) {
		
		var tableRow = $(this).closest("tr");
		

		if(numRows > 1){
			numRows--;
			tableRow.remove();
			updateTotal();
			
		} else {
			alert("You can't delete the only row!");
		}
		e.preventDefault();

	});
		
	//Calculate
	
	$("#invoice-table").on("input", function(e) {
	
		if(e.target.className !== "description") {
			updateTotal();
		}
					
	});
	
	//Update total function
	
	function updateTotal() {
		var subtotal = 0,

			iva = Number($(".iva").val()) / 100,
			irpf = Number($(".irpf").val()) / 100,
			totaliva,
			totalirpf;
			
		//Loop
		  $("#invoice-table > tbody > tr.row").each(function(){
          var quantity = $(this).find("input.cantidad").val(),
              cost = $(this).find("input.coste").val();
              price = +cost * +quantity;
          $(this).find(".precio").text(price);
          $(this).find(".precio-hidden").val(price);
          subtotal += price;
        });
		
		totaliva = roundToTwo(subtotal*iva);
		totalirpf = roundToTwo(subtotal*irpf);
		total = subtotal + totaliva + totalirpf;
		
		
		
		$(".subtotal").text(subtotal);
		$(".totaliva").text(totaliva);
		$(".totalirpf").text(totalirpf);
		$(".total").text(roundToTwo(total));
		//
		$(".subtotal-hidden").val(subtotal);
		$(".totaliva-hidden").val(totaliva);
		$(".totalirpf-hidden").val(totalirpf);
		$(".total-hidden").val(roundToTwo(total));


	}
	
	//Round function
	function roundToTwo(value) {
        return(Math.round(value * 100) / 100);
    }
    
    //Logo preview
    
    /*var thumb = $('img#thumb');        

	  new AjaxUpload('imageUpload', {
	    action: $('form#newHotnessForm').attr('action'),
	    name: 'image',
	    onSubmit: function(file, extension) {
	      $('div.preview').addClass('loading');
	    },
	    onComplete: function(file, response) {
	      thumb.load(function(){
	        $('div.preview').removeClass('loading');
	        thumb.unbind();
	      });
	      thumb.attr('src', response);
	    }
	  });*/

});


Thanks for your help.

Hi there,

As I mentioned, I don’t have any experience with this particular PDF library, so I would need a minimal example of how it works, so that I could understand it.

Could you post a minimal HTML page with one paragraph on it and one button. Nothing else.
Have it that when you press the button, it generates a PDF of the page and its contents.
You’ll probably have to point me to where I can get the relevant PHP files, too.

Sorry if this feels like a step backwards, but when tackling things like this, it is always best to reproduce your problem in the least possible amount of code.
Once we have a minimal example of the thing working, we can build it up to work (hopefully), as you would like.