Invoice Application Front-end Using ElectronJS-阿里云开发者社区

开发者社区> 芷沁> 正文

Invoice Application Front-end Using ElectronJS

简介: In part two of this three-part tutorial, we will explore how to create the front-end of a fully functional invoice application using ElectronJS.

By Sai Sarath Chandra, Alibaba Cloud Tech Share Author and Alibaba Cloud MVP

In our previous article, we discussed in detail about:

  • What ElectronJS is
  • Why you should opt for ElectronJS
  • Benefits and limitations of ElectronJS

We also briefly talked about how Electron handles a simple use case.

In this article, we will setup an ElectronJS based project, creating a user interface (UI) alongside ElectronJS functionalities. We will also go into detail as we create the functionality which forms the building blocks for any Electron application.

We will be using the Boomerang UI Kit, which is built on Bootstrap Framework. Bootstrap provides nice and customizable components, which can almost be used in any web development. The reason I choose Boomerang UI Kit is more of a personal choice. You can choose any other framework to work with this tutorial as we are more focusing only on the ElectronJS functionalities rather than the Frontend frameworks.

Creating an Electron Template

Let’s start with the basic version of the Electron Template. This is the GitHub link of the template forked from the Official Electron Repository. If you would like to experiment, then go ahead and clone the code by visiting this link:

Below is the file structure you should see after cloning the code.


Let's talk briefly about what each file is responsible for

Many have taken this file for granted, but the real purpose of the file is to ignore the files while committing / pushing the code to the git repository. This will make sure unnecessary files are not pushed into the repository.
This outlines the Licensing structure of the code you are releasing as an open source. Make sure you check all the licenses and pick what suits best for you
This is the front page you see when the repository is opened. The markdown is a special format of writing the documentation which is very easy with enough formatting options to make the content readable.

The file where we should keep our presentation logic. All the UI design with HTML and CSS should go here. It might happen we maintain different files or a single html page for the whole application based on the UI architecture you follow. There are also couple of changes you need to make to make sure your tag works, we will discuss that shortly.

This is the heart of the Electron application, this consists of the complete communication from the IPCMain process to the IPCRenderer process. We will see in detail how it works when we discuss the code. This file is responsible for all the Inter Process Communication.

This file should be familiar to you if you have experience with Node.js else this nothing but a file with a list of dependencies for production and development. The equivalent can also be found in java like pom.xml.

This is the renderer part of the Inter Process Communication. Note that you can have multiple renderer.js but not advisable to have multiple main.js as it very difficult to maintain and follow the chain of events.

Desktop Invoicing Application using ElectronJS

We are creating the Invoicing Application based on ElectronJS. We start by creating the UI for the application

I chose Boomerang UI Kit ( . This is created on top of bootstrap framework which provide easy way to develop responsive & beautiful User Interface. There are so many pre-defined code snippets which helps you get started.

The whole code snippets I show you today is taken from this repo below

Clone the code, and you should find "Electron_Invoice" and "Invoice_Backend". Electron_Invoice consists of the whole frontend code we are discussing in this article.

<link href=",600,700,800|Roboto:400,500,700" rel="stylesheet">
<!-- Theme CSS -->
<link type="text/css" href="./assets/css/theme.css" rel="stylesheet">
<!-- Font Awesome -->
<link href='' rel='stylesheet' type='text/css'>

We are linking theme.css, which contains all the needed CSS constructs for styling the elements of the basic Bootstrap framework. Linking CSS is straight forward as we do in web development

If we navigate to the end of the </body> tag you will find several scripts. One of which is

// You can also require other files to run in this process

Here we are injecting renderer.js, In renderer.js you can access complete DOM and NPM (Node Package Manager) modules.

if (typeof module === 'object') {
window.module = module;
module = undefined;
<!-- Start Script dependencies -->
<!-- Core -->
<script src="./assets/vendor/jquery/jquery.min.js"></script>
<script src="./assets/vendor/popper/popper.min.js"></script>
<script src="./assets/js/bootstrap/bootstrap.min.js"></script>
<!-- FontAwesome 5 -->
<script src="./assets/vendor/fontawesome/js/fontawesome-all.min.js" defer></script>
<!-- Page plugins -->
<script src="./assets/vendor/bootstrap-select/js/bootstrap-select.min.js"></script>
<script src="./assets/vendor/bootstrap-tagsinput/bootstrap-tagsinput.min.js"></script>
<script src="./assets/vendor/input-mask/input-mask.min.js"></script>
<script src="./assets/vendor/nouislider/js/nouislider.min.js"></script>
<script src="./assets/vendor/textarea-autosize/textarea-autosize.min.js"></script>
<!-- Theme JS -->
<script src="./assets/js/theme.js"></script>
<!-- Chart JS Plugin -->
<script src=""></script>
<!-- Mustache JS -->
<script src=""></script>
<!-- Ending Script dependencies -->
if (window.module) module = window.module;

This is the most important piece of code you need to understand as this hinders the dependencies to integrate properly. Note that before you start adding any .js dependencies, we need to add the script above the comment "starting script dependencies". If not, modules like JQuery and other libraries will not be available.

In Electron all the libraries should be available as modules. By enclosing the imports between the scripts of "Starting & Ending script dependencies". All are imported successfully and made available.

The imports we are using include:

Jquery, Popper, Bootstrap – for Boomerang UI interdependencies as the UI Kit is built on top of that.

Font Awesome – for fully scalable icons integrated as font.

Page plugins – These are used to creates an additional functionality to the existing elements we are using as part of html.

Theme – This JavaScript code is more bound with the theme.css which is also responsible for the animations, interpolations, etc...

ChartJS – We are using Chart JS for the showing the analytical analysis in the graphical form. This library is open-source and it provides a lot of charts which are easy to customize.

MustacheJS – We used Mustache to create html dynamically at runtime with ease. This library greatly simplifies the work of generating the dynamic html and replacing the values using a list.

Before I discuss any other code snippet, let's see how our end product would look like.




Sales Visualization

These are the two screens we are designing now:

  • New Invoice
    This is the window where we have a form to make user create a new invoice.
  • Dashboard
    Dashboard is where we see the user sales analysis, total orders and total sales in a graphical way.


The above UI Part is achieved by the following code:

<div class='navigationBar'>
        <ul class="nav nav-pills nav-fill flex-column flex-sm-row" id="myTab" role="tablist">
          <li class="nav-item">
            <a class="nav-link mb-sm-3 active" id="home-tab" data-toggle="tab" href="#newInvoice" role="tab" aria-controls="home" aria-selected="true">New Invoice</a>
          <li class="nav-item">
            <a class="nav-link mb-sm-3" id="profile-tab" data-toggle="tab" href="#dashboard" role="tab" aria-controls="profile" aria-selected="false">DashBoard</a>
        <div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="newInvoice" role="tabpanel" aria-labelledby="home-tab">
** Content of Home **
          <div class="tab-pane fade" id="dashboard" role="tabpanel" aria-labelledby="profile-tab">
** Content of DashBoard **

We follow the single page UI architecture wherein we will create the whole page at once in a single html file and we show that is needed.

If you see the “myTab” holds the complete list of tabs – New Invoice and Dashboard. You might ignore the Classes applied to the HTML Tags, they’re necessary else the tabs might not have the same presentation format.

The other <div>’s with “tab-pane” hold the content related to both “New Invoice” & “Dashboard”.

<div class="input-group-prepend">
   <span class="input-group-text">
       <i class="fas fa-user"></i>
<input type="text" class="form-control" id="customerName" placeholder="Customer Name">


This is one of the component that we used in the form, the icon will be created the tag and they are available with font awesome which we added earlier.



<table class="table">
              <thead class="thead-dark">
                  <th scope="col" class='centerme'>Item Details</th>
                  <th scope="col" class='centerme'>Qty</th>
                  <th scope="col" class='centerme'>Rate</th>
                  <th scope="col" class='centerme'>Amount</th>
                  <th scope="col"></th>

                    <div class="form-group">
                      <input type="text" id="itemDetails" class="form-control border-0" placeholder="Item Details">
                    <div class="form-group">
                      <input type="number" id="quantity" class="form-control border-0" placeholder="Quantity">
                    <div class="form-group">
                      <input type="number" id="rate" class="form-control border-0" placeholder="Rate">
                    <div class="form-group">
                      <input type="number" id="amount" class="form-control border-0" placeholder="Amount" readonly>
                  <td class=''>
                    <button type="button" onclick="addItemCard()" class="btn btn-success btn-icon-only rounded-circle">
                      <span class="btn-inner--icon">
                        <i class="fas fa-check"></i>

This particular piece of code creates the Table header & set of inputs along with the button against it.

The green button creates an entry with the Item details provided, then you can see the following entry


The card input with the Item Details are created with the following code

<!-- Template here Starts -->
<script id="tutorial-template" type="text/template">
  <tr class="bg-white">
    <th scope="row">
      <div class="media align-items-center">
        <span class="avatar avatar-lg bg-pink mr-3">{{itemShortName}}</span>
        <div class="media-body">
          <h6 class="h5 font-weight-normal mb-0">{{ItemName}}</h6>
          <span class="font-weight-normal text-muted">Quantity :
    <td>Rate/pc : {{rate}}</td>
    <td>Amount : {{amount}}</td>
  <tr class="table-divider"></tr>
<!-- Template here ends -->

This template is generated dynamically and added to the below table at runtime using the below function

function addItemCard() {
    var data = {};

    data.itemShortName = ($("#itemDetails").val()).substring(0, 2).toUpperCase();
    data.ItemName = $("#itemDetails").val();
    data.qty = $("#quantity").val();
    data.rate = $("#rate").val();
    data.amount = $("#amount").val();

    if (!itemsObj.customerName) {
      itemsObj.customerName = $("#customerName").val();

    if (!itemsObj.invoiceNumber) {
      itemsObj.invoiceNumber = $("#invoiceNumber").val();
    if (!itemsObj.invoiceDate) {
      itemsObj.invoiceDate = $("#invoiceDate").val();
    if (!itemsObj.dueDate) {
      itemsObj.dueDate = $("#dueDate").val();
    var template = $("#tutorial-template").html();
    var html = Mustache.render(template, data);


Upon clicking, “addItemCard()” will be invoked and the data is pushed into the ItemsObj (Which will be used later to push data into the server). It also creates the card template using the Mustache library and appends it to the table.

<table class="table table-hover table-cards align-items-center">
              <tbody id="cardsList">
                <!-- Dynamically generated template goes here -->

We have the “Reset” button which resets the complete data in the form to like a new Invoice form.

This is one more functionality where we will make an API call which takes care of inserting the data to the database.

function submitData() {
    console.log('submit Clicked');
    var itemsArr = itemsObj.itemsData;
    var totalAmount = 0;

    for (var i = 0; i < itemsArr.length; i++) {
      totalAmount = totalAmount + parseFloat(itemsArr[i].amount);
    itemsObj.totalAmount = totalAmount;

      type: 'POST',
      data: JSON.stringify(itemsObj),
      contentType: 'application/json',
      url: '',
      success: function (data) {

This is the POST Call to the above-mentioned URI, which is operating in the ECS Instance and takes care of inserting data into the MongoDB instance. We will discuss more about the backend soon.

The dashboard is made of below components


The above component is created using the following code:

<div class="card">
                  <div class="card-header">
                    <div class="row align-items-center">
                      <div class="col-8">
                        <h4 class="heading h5 mb-0">Today Orders</h4>
                      <div class="col-4">
                        <div class="card-icon-actions text-right">
                          <a href="#" class="favorite" data-toggle="tooltip" data-original-title="Save as favorite">
                            <i class="fas fa-star"></i>
                          <a href="#" class="love active" data-toggle="tooltip" data-original-title="Love this">
                            <i class="fas fa-heart"></i>
                  <div class="card-body">
                    <p class="card-text" id="saleCount">Count : 0</p>
                  <div class="card-footer">
                    <div class="row align-items-center">
                      <div class="col-6">
                        <a href="#" class="btn btn-sm btn-primary" onclick="fetchAndLoadValues()">Refresh Now</a>
                      <div class="col-6 text-right">
                        <span class="text-muted" id="saleCountUpdateValue">2 hrs ago</span>

The above code creates the Card with the icons, header and button along with the recent refreshed time from MongoDB.

We have also used the chart.js for the Graphical representation of the sales with the respective dates. You can see that in the script section under the

tag for reference. It should be very obvious.

We will discuss the functionality we have used to fetch data and analyze in the code

  function fetchAndLoadValues() {
    var ajaxResult = {};
      url: "", success: function (result) {
        ajaxResult = result; = ajaxResult.datesArr;[0].data = ajaxResult.salesArr;
        $('#saleValue').text("sale Value : $ " + (ajaxResult.salesArr)[0]);
        $('#saleCount').text("Count : " + (ajaxResult.ordersArr)[0]);

The “fetchAndLoadValues()” function will make an AJAX (Asyncronous Javascript and XML) call to the API on ECS instance and fetches the values and do the below operations

  • Update the value of Sale Value refresh Time
  • Update the value of Total Orders Count update time
  • The total sale Value of the current day
  • Total order count of all the orders on that day
  • Creating an array of total sale value & dates of the previous 5 days for the graph

What's Next?

We will be discussing the how we created the backend services used for this application and what operations we can perform with our application. If you haven't read about the benefits of Electron, then you should definitely check out the previous article from this tutorial series.


如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
4150 0
7436 0
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4623 0
8269 0
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
9516 0
阿里云ECS云服务器初始化是指将云服务器系统恢复到最初状态的过程,阿里云的服务器初始化是通过更换系统盘来实现的,是免费的,阿里云百科网分享服务器初始化教程: 服务器初始化教程方法 本文的服务器初始化是指将ECS云服务器系统恢复到最初状态,服务器中的数据也会被清空,所以初始化之前一定要先备份好。
3665 0
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
17387 0