Tutorial: Building an Invoice Template with MaterializeCSS and Jquery
utopian-io·@gotgame·
0.000 HBDTutorial: Building an Invoice Template with MaterializeCSS and Jquery
#### Repository https://github.com/olatundeee #### What Will I Learn? In this tutorial we will learn how to perform the following operations on the client side of our web applications - Get and store the value of form inputs - Output the value of form inputs in our browser In addition we will be implementing an invoice template that can be used by businesses to issue receipts and invoices to their customers. #### Requirements - [Ionicons Library For Icons](http://ionicons.com/) - [JQuery Library](https://jquery.com/) - [MaterializeCSS Framework](https://next.materialize.com/) - You can download the full source code for this tutorial on [Github](https://github.com/olatundeee/invoice-template) #### Difficulty - Basic #### Tutorial Contents Before starting out we have to setup MaterializeCSS and other dependencies for this tutorial (jquery and ionicons). Information on how to do that can be found in my earlier tutorial on [how to build a landing page with MaterializeCSS](https://steemit.com/utopian-io/@gotgame/building-a-landing-page-with-materializecss-1). After setting up materialize the next step is to build our template. The template is divided into three sections including 1. Header which contains addresses of both buyer and seller 2. Input form where the seller can enter details about the products including the product name, price and quantity bought. This form will feature a submit button which when clicked will update a list directly below the form with the data entered into the form. 3. The third part of the form will contain a list of products and information about each updated through the form. After the entire process we should have a simple interface like the one below    Let's create our template. The HTML code for creating this template ```markup <!DOCTYPE html> <html> <head> <!--Import Google Icon Font--> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> <!--Import materialize.css--> <link type="text/css" rel="stylesheet" href="css/materialize.css" media="screen,projection"/> <link type="text/css" rel="stylesheet" href="css/invoice.css" media="screen,projection"/> <link type="text/css" rel="stylesheet" href="css/ionicons.css" media="screen,projection"/> <!--Let browser know website is optimized for mobile--> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> </head> <body> <div class="container invoice-body"> <div class="row"> <div class="col l6 m6 s12 left-align"> <p> Lorem Ipsum Company<br> P.O. Box 18728, Non-Conformity Way<br> Someplace Somewhere<br> VAT No: 2617 348 2752<br> </p> </div> <div class="col l6 m6 s12 right-align"> <p> Billed To:<br> Sam Donald Ripley<br> Also Living Somewhere PO Box 29618<br> VAT No: 295 3932 6119<br> </p> </div> <div class="col l6 m6 s12 left-align"> <p><strong>Invoice No:</strong> A - 21637</p> </div> <div class="col l6 m6 s12 right-align"> <p><strong>Invoice Date:</strong> 07/06/2018</p> </div> <div class="col l12 m12 s12 invoice-header center-align"> <h4>INVOICE</h4> </div> <div class="col l12 m12 s12 invoice-sub-header-input center-align grey lighten-3"> <div class="container"> <div class="row"> <form action="" class="col l12 m12 s12"> <div class="row invoice-sub-header-form"> <div class="input-field col l12 m12 s12"> <input placeholder="Item" id="item_sold" type="text" class="black-text invoice-input-form"> </div> <div class="input-field col l6 m6 s12"> <input placeholder="Price" id="price_sold" type="number" class="black-text invoice-input-form-half"> </div> <div class="input-field col l6 m6 s12"> <input placeholder="Quantity" id="quantity_sold" type="number" class="black-text invoice-input-form-half"> </div> </div> </form> <div class="submit-button center"> <a class="waves-effect waves-light btn add-new-item"><i class="ion-android-add left"></i>ADD ITEM</a> </div> </div> </div> </div> <div class="col l12 m12 s12 invoice-sub-header-output center-align"> <div class="container item-details-output"> </div> <div class="container right"> <p class="net-total"></p> </div> </div> </div> </div> <!--JavaScript at end of body for optimized loading--> <script type="text/javascript" src="js/jquery.js"></script> <script type="text/javascript" src="js/materialize.js"></script> <script type="text/javascript" src="js/invoice.js"></script> </body> </html> ``` --- The CSS code for our template ```markup body { background: #eeeeee; } .invoice-body { margin-top: 100px; margin-bottom: 100px; border: 1px solid #000; padding: 50px; background: #fff; color: #757575; } .invoice-header { margin-top: 100px; } .invoice-sub-header-input { margin-top: 50px; } .invoice-sub-header-output { margin-top: 50px; } .invoice-input-form { border: 1px solid #000 !important; padding-left: 20px !important; } .invoice-input-form-half { border: 1px solid #000 !important; padding-left: 10px !important; margin-left: 3px !important; } #item_sold:focus { border: 1px solid #000 !important; } .invoice-sub-header-form { margin-top: 30px; } .item-details { margin-top: -25px !important; width: 185.7px !important; } .item-details-data { margin-top: -15px !important; } .item-header { padding: 15px; } ``` --- In the `<body></body>` tag for our html we have we first of all create a container for all elements to give the layout a closely packed look. The container is created using this syntax `<div class="container invoice-body"></div>` The class attribute `invoice-body` is responsible for setting the following styles in our CSS file ``` .invoice-body { margin-top: 100px; margin-bottom: 100px; border: 1px solid #000; padding: 50px; background: #fff; color: #757575; } ``` To create the header/address section we create a new row with the following tag ``` <div class="row"></div> ``` Inside our row the first column contains a paragraph holding the address of the invoice sender. This column was created using the following tag ``` <div class="col l6 m6 s12 left-align"> <p> Lorem Ipsum Company<br> P.O. Box 18728, Non-Conformity Way<br> Someplace Somewhere<br> VAT No: 2617 348 2752<br> </p> </div> ``` ---- The second column was created using the same template as above and it holds the address of the buyer. The code for this column is as thus ``` <div class="col l6 m6 s12 right-align"> <p> Billed To:<br> Sam Donald Ripley<br> Also Living Somewhere PO Box 29618<br> VAT No: 295 3932 6119<br> </p> </div> ``` ---- In both column the class attributes `left-align` and `right-align` will align the text contents of both columns to the left and right respectively. We add additional information to the header section by creating two new columns just like the ones we created earlier The code for this new columns ``` <div class="col l6 m6 s12 left-align"> <p><strong>Invoice No:</strong> A - 21637</p> </div> <div class="col l6 m6 s12 right-align"> <p><strong>Invoice Date:</strong> 07/06/2018</p> </div> ``` ---- Each newly added column contains a paragraph and some text content as can be seen in the code above Here is a screenshot of the section after it has been created  ---- Next we add the form that will be responsible for inputting values that will be collated as item information for each sold product. To create the form area we use the following code ``` <div class="col l12 m12 s12 invoice-sub-header-input center-align grey lighten-3"> <div class="container"> <div class="row"> <form action="" class="col l12 m12 s12"> <div class="row invoice-sub-header-form"> <div class="input-field col l12 m12 s12"> <input placeholder="Item" id="item_sold" type="text" class="black-text invoice-input-form"> </div> <div class="input-field col l6 m6 s12"> <input placeholder="Price" id="price_sold" type="number" class="black-text invoice-input-form-half"> </div> <div class="input-field col l6 m6 s12"> <input placeholder="Quantity" id="quantity_sold" type="number" class="black-text invoice-input-form-half"> </div> </div> </form> <div class="submit-button center"> <a class="waves-effect waves-light btn add-new-item"><i class="ion-android-add left"></i>ADD ITEM</a> </div> </div> </div> </div> ``` The form section was opened using ``` <div class="col l12 m12 s12 invoice-sub-header-input center-align grey lighten-3"></div> ``` The class attribute `invoice-sub-header-input` will set the following CSS styles for our form section. ``` .invoice-sub-header-input { margin-top: 50px; } ``` A container and a new row that will hold the contents of our form was added using the following syntax. ``` <div class="container"> <div class="row"> </div> </div> ``` Inside the new row we have a full-width form. This was achieved using the following HTML tag ``` <form action="" class="col l12 m12 s12"></form> ``` The contents of our `<form></form>` tag are housed in a row created using `<div></div>` with a class attribute of `invoice-sub-header-form` which sets the following CSS styles for this section ``` .invoice-input-form { border: 1px solid #000 !important; padding-left: 20px !important; } ``` The new row contains three text inputs and each was created using ``` <div class="input-field col l12 m12 s12"> <input type="text"> </div> ``` The only distinctions among these three text inputs lies in their `id` and `class` attributes All three forms have the `id` attribute values `item_sold, price_sold and quantity_sold` respectively. The first text input has a class attribute value `invoice-input-form` while the remaining two have a class value attribute `invoice-input-form-half` The CSS styles being handled by `invoice-input-form` have been referred to above, as for `invoice-input-form-half` the following are the CSS styles it is responsible for ``` .invoice-input-form-half { border: 1px solid #000 !important; padding-left: 10px !important; margin-left: 3px !important; } ``` Here is a screenshot of the form section after it has been created  Directly below our form we create another fullwidth column using the syntax ``` <div class="col l12 m12 s12 invoice-sub-header-output center-align"> <div class="container item-details-output"> </div> </div> ``` There is only one notable class attribute linked to this section, this class attribute is the `invoice-sub-header-output` which is responsible for the following CSS styles ``` .invoice-sub-header-output { margin-top: 50px; } ``` The contents of this section will be added dynamically using Jquery, what we want is for the contents of this section to be updated every time the appropriate values are entered in the form section above it and the button with the text `ADD ITEM` is clicked. The following is the JavaScript code responsible for the contents of this section ``` $(document).ready(function() { $('.add-new-item').click(function () { var itemName = $('#item_sold').val(); // Value for item sold var itemPrice = $('#price_sold').val(); // Price per each item sold var itemQuantity = $('#quantity_sold').val(); // Quantity sold per item var itemTotal = itemPrice * itemQuantity; // Total price of item sold var newItemRow = '<div class="container item-details-output"><div class="col l12 m12 s12"><h5 class="center-align grey lighten-1 item-header item-name"></h5></div><div class="col l4 m4 s12 item-details"><p class="center-align grey lighten-3">Price per Item</p><p class="center-align grey lighten-2 item-details-data item-price"></p></div><div class="col l4 m4 s12 item-details"><p class="center-align grey lighten-3">Quantity</p><p class="center-align grey lighten-2 item-details-data item-quantity"></p></div><div class="col l4 m4 s12 item-details"><p class="center-align grey lighten-3">Total Sold</p><p class="center-align grey lighten-2 item-details-data item-total"></p></div></div>'; // Add new element $('.invoice-sub-header-output').append([newItemRow]); $('.item-name').text('Product: ' + itemName); $('.item-price').text('$' + itemPrice); $('.item-quantity').text(itemQuantity); $('.item-total').text('$' + itemTotal); $('.item-name').removeClass('item-name'); $('.item-price').removeClass('item-price'); $('.item-quantity').removeClass('item-quantity'); $('.item-total').removeClass('item-total'); }); }); ``` The opening function for these Jquery script `$(document).ready(function() {});` will prevent the script from running until the HTML document has finished loading and the script is ready to be used. Inside this opening function we have another function `$('.add-new-item').click(function () {});`. What this expression states is just that whenever the element with the class attribute `.add-new-item` is clicked. The `click()` is nothing more than a Jquery event listener which notifies the script that the specified element has been clicked and then goes on to provide the set of statements to be executed in that instance. When the element in question is clicked the following happens sequentially - First, the script gets the value of current contents of the text inputs in the form we created earlier and stores each one in a variable. This is done using the following statements ``` var itemName = $('#item_sold').val(); var itemPrice = $('#price_sold').val(); var itemQuantity = $('#quantity_sold').val(); var itemTotal = itemPrice * itemQuantity; ``` Each variable highlighted above stores the value of an input value. However the last variable `itemTotal` doesn't do so directly, instead it stores the result of multiplying the values of the variables `itemPrice` and `itemQuantity`. In the first three variables above, the `.val()` function gets and stores the value of any form element indicated in the parentheses before it. We also have an additional variable in the script storing a different type of value. The value being stored here is the HTML template to be used by the script to output data collected in the form for each product to be included in the invoice. ``` var newItemRow = '<div class="container item-details-output"><div class="col l12 m12 s12"><h5 class="center-align grey lighten-1 item-header item-name"></h5></div><div class="col l4 m4 s12 item-details"><p class="center-align grey lighten-3">Price per Item</p><p class="center-align grey lighten-2 item-details-data item-price"></p></div><div class="col l4 m4 s12 item-details"><p class="center-align grey lighten-3">Quantity</p><p class="center-align grey lighten-2 item-details-data item-quantity"></p></div><div class="col l4 m4 s12 item-details"><p class="center-align grey lighten-3">Total Sold</p><p class="center-align grey lighten-2 item-details-data item-total"></p></div></div>'; ``` Every vital element in the template featured above has a class attribute value that will be used to identify and manipulate it in the rest of the script. After creating this template variable, the script is then instructed to append the value of the variable to the page contents. This is achieved using the following syntax ``` $('.invoice-sub-header-output').append([newItemRow]); ``` What the above statement translates to is that the contents of the variable `newItemRow`should be appended using the Jquery `append()` function inside the element with a class of `.invoice-sub-header-output`. We then set the values for the contents of the template by adding the following ``` $('.item-name').text('Product: ' + itemName); $('.item-price').text('$' + itemPrice); $('.item-quantity').text(itemQuantity); $('.item-total').text('$' + itemTotal); ``` `.text()` is a jquery function that is usually used to set the contents of A HTML element. In our created program `$('.item-name').text('Product: ' + itemName);` will set the text content of the element with a class attribute `.item-name` to the value of the variable `itemName`. `$('.item-price').text('$' + itemPrice);` will set the text content of the element with a class attribute `.item-price` to the value of the variable `itemPrice`. `$('.item-quantity').text(itemQuantity);` will set the text content of the element with a class attribute `.item-quantity` to the value of the variable `itemQuantity`. And finally, `$('.item-total').text('$' + itemTotal);` will set the text content of the element with a class attribute `.item-total` to the value of the variable `itemTotal`. Now whenever we enter a new set of values into the form area and click on the button `ADD LINK` the template added in our script will be appended and the new values entered in the form will be set as its text content as designated. We have one final line of action, whenever the button is clicked you might notice that instead of the new values to be included in the newly appended template it actually updates all of the values of the templates appended before that to the new values. To prevent this from happening we then proceed to remove the classes responsible for setting the text contents in the script after each template has been appended. This is achieved using the Jquery `removeClass()` function. The code below would help us get that done. ``` $('.item-name').removeClass('item-name'); $('.item-price').removeClass('item-price'); $('.item-quantity').removeClass('item-quantity'); $('.item-total').removeClass('item-total'); ``` `removeClass()` is a Jquery function that is used to remove a previously set class attribute value from a HTML element. What the code above does is that it simply picks the element with the specified class and after it does that it then removes any indicated class from the HTML element. That way any future append operation will not affect previous appends since the class attribute value responsible for that has been removed. Below is a screenshot of the section we just created after some values have been added with the form  #### Curriculum 1. [Simple Shopping Cart Using Vue.js and Materialize - 2](https://steemit.com/utopian-io/@gotgame/simple-shopping-cart-using-vue-js-and-materialize-2) 2. [Simple Shopping Cart using Vuejs and MaterializeCSS - 1](https://steemit.com/utopian-io/@gotgame/simple-shopping-cart-using-vue-js-and-materialize) 3. [Building a Landing Page with MaterializeCSS - 2](https://steemit.com/utopian-io/@gotgame/building-a-landing-page-with-materializecss-2) 4. [Building a Landing Page with MaterializeCSS - 1](https://steemit.com/utopian-io/@gotgame/building-a-landing-page-with-materializecss-1) #### Proof Of Work Done https://github.com/olatundeee/invoice-template
👍 jalasem, iamowomizz, iretiolajohnson, nerdgarage, rashyem, steemitstats, yuxi, leir, romansilenkov, ermakx, rodionrasaev, ricklargo, svetamihanova, homesickhow, trekkingglucose, skimmingfind, borealisquirt, ruex, bithumb-hot, gopax-dposit, myuupbit, boomeerang, roocky1, ivan.gotovin, filinenok, modulardrudge, ivankash, ismaelahr, iridiumnonagon, poofwalrus, ahullcortege, daileyfre, jhendrych, ropessecond, backpackflu, polygontackle, elidirbrown, chewycareless, makarova12, ostpromoter, goapx-deposit, ubildawhale, gopa-deposit, gopax-deopsit, gopax-depsoit, postpromoer, postproomoter, penledger-dex, edepcrypto8, smartsteme, smmartsteem, openledgre-dex, potspromoter, bithuumb.hot, gopax-depositt, openledgr-dex, gopax-depposit, postpromooter, jaff8, tdre, properfraction, achiron, gotgame, steemdunk, utopian-io, condeas,