3
\$\begingroup\$

I am developing a microservice that enables business partners to order systems for common customers:

/*
 ordering.js - Terminal ordering JavaScript library.
 (C) 2017 HOMEINFO - Digitale Informationssysteme GmbH
 This library is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with this library. If not, see <http://www.gnu.org/licenses/>.
 Maintainer: Richard Neumann <r dot neumann at homeinfo period de>
 Requires:
 * jquery.js
 * sweetalert.js
 * homeinfo.js
 * his.js
*/
'use strict';
var ordering = ordering || {};
/*
 Static globals.
*/
ordering._BASE_URL = 'https://top.secret.com/endpoint';
ordering._ORDERS_ENDPOINT = ordering._BASE_URL + '/order';
ordering._CUSTOMERS_ENDPOINT = ordering._BASE_URL + '/customers';
ordering._CLASSES_ENDPOINT = ordering._BASE_URL + '/classes';
ordering._OSS_ENDPOINT = ordering._BASE_URL + '/oss';
/*
 Runtime globals.
*/
ordering.orders = ordering.orders || [];
ordering.customers = ordering.customers || [];
ordering.classes = ordering.classes || [];
ordering.oss = ordering.oss || [];
/*
 Displays an error using sweetalert.
*/
ordering.error = function (title, text, type) {
 return function () {
 swal({
 title: title,
 text: text,
 type: type || 'error'
 });
 };
};
/*
 Queries orders from the API.
*/
ordering._getOrders = function () {
 return his.auth.get(ordering._ORDERS_ENDPOINT).then(
 function (orders) {
 ordering.orders = orders;
 },
 ordering.error('Fehler.', 'Konnte verfügbare Bestellungen nicht abfragen.')
 );
};
/*
 Queries customers from the API.
*/
ordering._getCustomers = function () {
 return his.auth.get(ordering._CUSTOMERS_ENDPOINT).then(
 function (customers) {
 ordering.customers = customers;
 },
 ordering.error('Fehler.', 'Konnte verfügbare Kunden nicht abfragen.')
 );
};
/*
 Queries classes from the API.
*/
ordering._getClasses = function () {
 return his.auth.get(ordering._CLASSES_ENDPOINT).then(
 function (classes) {
 ordering.classes = classes;
 },
 ordering.error('Fehler.', 'Konnte verfügbare Terminal-Klassen nicht abfragen.')
 );
};
/*
 Queries classes from the API.
*/
ordering._getOSs = function () {
 return his.auth.get(ordering._OSS_ENDPOINT).then(
 function (oss) {
 ordering.oss = oss;
 },
 ordering.error('Fehler.', 'Konnte verfügbare Betriebssysteme nicht abfragen.')
 );
};
/*
 Performs a HIS login.
*/
ordering._login = function () {
 var queryString = new homeinfo.QueryString();
 return his.session.login(queryString.userName, queryString.passwd);
};
/*
 Initializes the page.
*/
ordering.init = function () {
 ordering._login().then(
 ordering._getData().then(
 ordering._initPage
 )
 );
};
/*
 Submit form.
*/
ordering._submitForm = function (event) {
 event.preventDefault(); // Avoid to execute the actual submit of the form.
 his.auth.post(ordering._ORDERS_ENDPOINT, jQuery('#orders').serialize()).then(ordering._resetForm);
};
/*
 Resets the form.
*/
ordering._resetForm = function () {
 document.getElementById('orders').reset();
 ordering.init();
};
/*
 Initialization function.
*/
ordering._getData = function () {
 var getOrders = ordering._getOrders();
 var getCustomers = ordering._getCustomers();
 var getClasses = ordering._getClasses();
 var getOSs = ordering._getOSs();
 return Promise.all([getOrders, getCustomers, getClasses, getOSs]);
};
/*
 Refreshes the orders list.
*/
ordering._renderList = function () {
 var tableContainer = document.getElementById('tableContainer');
 tableContainer.innerHTML = '';
 tableContainer.appendChild(ordering._dom.list());
};
/*
 Renders the orders input.
*/
ordering._renderOrders = function () {
 var formContainer = document.getElementById('formContainer');
 formContainer.innerHTML = '';
 formContainer.appendChild(ordering._dom.orders());
};
/*
 Initializes the page.
*/
ordering._initPage = function () {
 ordering._renderList();
 ordering._renderOrders();
 jQuery('#orders').submit(ordering._submitForm);
};
/*
 Deletes the respective order.
*/
ordering._deleteOrder = function (id) {
 return his.auth.delete(ordering._ORDERS_ENDPOINT + '/' + id).then(ordering._getData).then(ordering._renderList);
};
/*
 Adds an order.
*/
ordering._addOrderForm = function () {
 var orderForms = document.getElementById('orderForms');
 var order = ordering._dom.order(true);
 orderForms.appendChild(order);
};
/*
 Deletes the respective order form.
*/
ordering._deleteOrderForm = function (index) {
 var orderForms = document.getElementById('orderForms');
 var order = document.getElementById('order_' + index);
 orderForms.removeChild(order);
};
/*
 DOM model.
*/
ordering._dom = ordering._dom || {};
ordering._dom.COLUMNS = [
 'Konto', 'Bestelldatum', 'Bearbeitungsstatus', 'Kunde', 'Klasse', 'Betriebssystem', 'Adresse', 'Anmerkung',
 'Stornieren'];
/*
 ID of orders form.
*/
ordering._dom.ORDERS = 0;
/*
 Builds an order set.
*/
ordering._dom.orders = function () {
 var form = document.createElement('form');
 form.setAttribute('id', 'orders');
 var orderForms = document.createElement('div');
 orderForms.setAttribute('id', 'orderForms');
 orderForms.setAttribute('class', 'row row-center');
 var firstOrder = ordering._dom.order();
 orderForms.appendChild(firstOrder);
 form.appendChild(orderForms);
 form.appendChild(ordering._dom.buttonAddOrderForm());
 form.appendChild(document.createTextNode(' '));
 form.appendChild(ordering._dom.submit());
 return form;
};
/*
 Creates a button to add an order form input for a further terminal.
*/
ordering._dom.buttonAddOrderForm = function () {
 var button = document.createElement('button');
 button.setAttribute('class', 'btn btn-success');
 button.setAttribute('onclick', 'ordering._addOrderForm();');
 button.textContent = 'Weiteres Terminal hinzufügen.';
 return button;
};
/*
 Creates a button to delete the respective oder inputs.
*/
ordering._dom.buttonDeleteOrderForm = function (index) {
 var buttonDeleteOrderForm = document.createElement('button');
 buttonDeleteOrderForm.setAttribute('onclick', 'ordering._deleteOrderForm(' + index + ');');
 buttonDeleteOrderForm.setAttribute('class', 'btn btn-danger');
 buttonDeleteOrderForm.textContent = 'X';
 return buttonDeleteOrderForm;
};
/*
 Creates a button to delete the respective order.
*/
ordering._dom.buttonDeleteOrder = function (id) {
 var button = document.createElement('button');
 button.setAttribute('class', 'btn btn-danger');
 button.setAttribute('onclick', 'ordering._deleteOrder(' + id + ');');
 button.textContent = 'X';
 return button;
};
/*
 Creates the title for the terminal order.
*/
ordering._dom.caption = function (index, additional) {
 var caption = document.createElement('legend');
 var textNode = document.createTextNode('Terminal ');
 caption.appendChild(textNode);
 if (additional) {
 caption.appendChild(ordering._dom.buttonDeleteOrderForm(index));
 }
 return caption;
};
/*
 Builds a single order.
*/
ordering._dom.order = function (additional) {
 if (additional == null) {
 additional = false;
 }
 var index = ordering._dom.ORDERS;
 ordering._dom.ORDERS += 1;
 var order = document.createElement('fieldset');
 order.setAttribute('id', 'order_' + index);
 order.setAttribute('class', 'row');
 var caption = ordering._dom.caption(index, additional);
 order.appendChild(caption);
 var columnSelects = document.createElement('div');
 columnSelects.setAttribute('class', 'col-md-6');
 var customerSelect = ordering._dom.customerSelect(index);
 columnSelects.appendChild(customerSelect);
 var classSelect = ordering._dom.classSelect(index);
 columnSelects.appendChild(classSelect);
 var osSelect = ordering._dom.osSelect(index);
 columnSelects.appendChild(osSelect);
 var columnAddress = document.createElement('div');
 columnAddress.setAttribute('class', 'col-md-6');
 var address = ordering._dom.address(index);
 columnAddress.appendChild(address);
 order.append(columnSelects);
 order.append(columnAddress);
 return order;
};
/*
 Builds a default option for a dropdown list.
*/
ordering._dom.defaultOption = function (text) {
 var defaultOption = document.createElement('option');
 var attributeSelected = document.createAttribute('selected');
 defaultOption.setAttributeNode(attributeSelected);
 var attributeDisabled = document.createAttribute('disabled');
 defaultOption.setAttributeNode(attributeDisabled);
 defaultOption.textContent = text;
 return defaultOption;
};
/*
 Builds the customer selection dropdown menu.
*/
ordering._dom.customerSelect = function (index) {
 var select = document.createElement('select');
 select.setAttribute('required', true);
 select.setAttribute('name', 'customer_' + index);
 select.setAttribute('class', 'form-control');
 var defaultOption = ordering._dom.defaultOption('Kunde*');
 select.appendChild(defaultOption);
 for (var i = 0; i < ordering.customers.length; i++) {
 var customer = ordering.customers[i];
 var option = document.createElement('option');
 option.setAttribute('value', customer.id);
 option.textContent = customer.company.name;
 select.appendChild(option);
 }
 return select;
};
/*
 Builds the class selection dropdown menu.
*/
ordering._dom.classSelect = function (index) {
 var select = document.createElement('select');
 select.setAttribute('required', true);
 select.setAttribute('name', 'class_' + index);
 select.setAttribute('class', 'form-control');
 var defaultOption = ordering._dom.defaultOption('Klasse*');
 select.appendChild(defaultOption);
 for (var i = 0; i < ordering.classes.length; i++) {
 var class_ = ordering.classes[i];
 var option = document.createElement('option');
 option.setAttribute('value', class_.id);
 option.textContent = class_.full_name;
 select.appendChild(option);
 }
 return select;
};
/*
 Builds the operating system selection dropdown menu.
*/
ordering._dom.osSelect = function (index) {
 var select = document.createElement('select');
 select.setAttribute('required', true);
 select.setAttribute('name', 'os_' + index);
 select.setAttribute('class', 'form-control');
 var defaultOption = ordering._dom.defaultOption('Betriebssystem*');
 select.appendChild(defaultOption);
 for (var i = 0; i < ordering.oss.length; i++) {
 var os = ordering.oss[i];
 var option = document.createElement('option');
 option.setAttribute('value', os.id);
 option.textContent = os.name + ' ' + os.version;
 select.appendChild(option);
 }
 return select;
};
/*
 Builds the address input fields.
*/
ordering._dom.address = function (index) {
 var address = document.createElement('fieldset');
 address.setAttribute('class', 'form-group');
 var street = document.createElement('input');
 street.setAttribute('type', 'text');
 street.setAttribute('required', true);
 street.setAttribute('name', 'street_' + index);
 street.setAttribute('placeholder', 'Straße*');
 address.appendChild(street);
 var houseNumber = document.createElement('input');
 houseNumber.setAttribute('type', 'text');
 houseNumber.setAttribute('required', true);
 houseNumber.setAttribute('name', 'houseNumber_' + index);
 houseNumber.setAttribute('placeholder', 'Hausnummer*');
 address.appendChild(houseNumber);
 var zipCode = document.createElement('input');
 zipCode.setAttribute('type', 'text');
 zipCode.setAttribute('required', true);
 zipCode.setAttribute('name', 'zipCode_' + index);
 zipCode.setAttribute('placeholder', 'PLZ*');
 address.appendChild(zipCode);
 var city = document.createElement('input');
 city.setAttribute('type', 'text');
 city.setAttribute('required', true);
 city.setAttribute('name', 'city_' + index);
 city.setAttribute('placeholder', 'Ort*');
 address.appendChild(city);
 var annotation = document.createElement('input');
 annotation.setAttribute('type', 'text');
 annotation.setAttribute('name', 'annotation_' + index);
 annotation.setAttribute('placeholder', 'Anmerkung');
 address.appendChild(annotation);
 return address;
};
/*
 Builds a submit button.
*/
ordering._dom.submit = function () {
 var submit = document.createElement('input');
 submit.setAttribute('type', 'submit');
 submit.setAttribute('value', 'Kostenpflichtig bestellen.');
 submit.setAttribute('class', 'btn btn-primary');
 return submit;
};
/*
 Builds the list of existing orders.
*/
ordering._dom.list = function () {
 var table = document.createElement('table');
 table.setAttribute('id', 'list');
 table.setAttribute('class', 'table table-hover');
 var thead = document.createElement('thead');
 var tr = document.createElement('tr');
 var th;
 for (var i = 0; i < ordering._dom.COLUMNS.length; i++) {
 th = document.createElement('th');
 th.setAttribute('scope', 'col');
 th.textContent = ordering._dom.COLUMNS[i];
 tr.appendChild(th);
 }
 thead.appendChild(tr);
 var tbody = document.createElement('tbody');
 var empty = true;
 for (var attr in ordering.orders) {
 if (ordering.orders.hasOwnProperty(attr)) {
 empty = false;
 tbody.appendChild(ordering._dom.listItem(ordering.orders[attr]));
 }
 }
 if (empty) {
 var h2 = document.createElement('h2');
 h2.setAttribute('align', 'center');
 h2.textContent = 'Keine Bestellungen vorhanden.';
 return h2;
 }
 table.appendChild(thead);
 table.appendChild(tbody);
 return table;
};
/*
 Builds the list items for each existing order.
*/
ordering._dom.listItem = function (order) {
 var row = document.createElement('tr');
 var columnAccount = document.createElement('td');
 columnAccount.textContent = order.account.name;
 row.appendChild(columnAccount);
 var columnIssued = document.createElement('td');
 columnIssued.textContent = order.issued;
 row.appendChild(columnIssued);
 var columnAccepted = document.createElement('td');
 var notProcessedYet = 'Noch nicht bearbeitet.';
 switch (order.accepted) {
 case null:
 columnAccepted.textContent = notProcessedYet;
 break;
 case undefined:
 columnAccepted.textContent = notProcessedYet;
 break;
 case true:
 columnAccepted.textContent = 'Angelegt.';
 break;
 case false:
 columnAccepted.textContent = 'Auftrag abgewiesen.';
 break;
 }
 row.appendChild(columnAccepted);
 var columnCustomer = document.createElement('td');
 columnCustomer.textContent = order.customer.company.name + ' (' + order.customer.id + ')';
 row.appendChild(columnCustomer);
 var columnClass = document.createElement('td');
 columnClass.textContent = order.class_.name;
 row.appendChild(columnClass);
 var columnOs = document.createElement('td');
 columnOs.textContent = order.os.name + ' ' + order.os.version;
 row.appendChild(columnOs);
 var columnAddress = document.createElement('td');
 var address = order.address;
 columnAddress.textContent = address.street + ' ' + address.house_number + ', ' + address.zip_code + ' ' + address.city;
 row.appendChild(columnAddress);
 var columnAnnotation = document.createElement('td');
 columnAnnotation.textContent = order.annotation || '-';
 row.appendChild(columnAnnotation);
 var columnDelete = document.createElement('td');
 columnDelete.appendChild(ordering._dom.buttonDeleteOrder(order.id));
 row.appendChild(columnDelete);
 return row;
};
jQuery(document).ready(ordering.init);

The corresponsing HTML document is:

<!DOCTYPE HTML>
<head>
 <meta charset="utf-8"/>
 <title>Terminal Bestellung</title>
 <link rel="stylesheet" href="https://libraries.homeinfo.de/bootstrap/latest/css/bootstrap.min.css">
 <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
 <link rel="stylesheet" href="https://libraries.homeinfo.de/sweetalert/dist/sweetalert.css">
 <script src="https://libraries.homeinfo.de/jquery/jquery-latest.min.js"></script>
 <script src="https://libraries.homeinfo.de/bootstrap/latest/js/bootstrap.min.js"></script>
 <script src="https://libraries.homeinfo.de/sweetalert/dist/sweetalert.min.js"></script>
 <script src="https://javascript.homeinfo.de/homeinfo.min.js"></script>
 <script src="https://javascript.homeinfo.de/his/his.js"></script>
 <script src="https://javascript.homeinfo.de/his/session.js"></script>
 <script src="ordering.js"></script>
</head>
<body>
 <h1 align="center">Ihre Bestellungen bei HOMEINFO</h1>
 <br>
 <div class="container">
 <div id="tableContainer" class="row"></div>
 <br>
 <div id="formContainer" class="row"></div>
 </div>
</body>

I'd like to have general feedback especially on the JavaScript code.

asked Aug 6, 2018 at 12:29
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

If you ask for specific questions, we can provide better feedback.

A few thoughts:

  • if you're including jQuery, go ahead and use it for DOM generation, as it will be much more concise and readable, instead of all the bulky createElement, setAttribute code. And the event handlers can be done through jQuery a little nicer.
  • if you're allowed, you have good names for the functions in the comments, and I'd use them. For example, listItem would be more clearly buildListItem; ordering._dom.list would probably be better buildExistingOrdersTable (it's not a list!). I would find buildSubmitButton clearer than ordering._dom.submit.
answered Aug 13, 2018 at 2:59
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.