2
\$\begingroup\$

I simulated a web shopping basket for a store with a single product, for two reasons:

  1. to learn to use browser events for a user to manipulate data in a page
  2. so that, in the future, I can build it into an Ethereum demo <screenshot>

A user can only do two things: fill a basket, and submit an order. The only part of order processing that I simulated is stock control, which I did entirely in the browser.

To run, all you need is a browser: there is no server-side code.

It works, there are no bugs that I know of, and I fixed all the issues that jslint and html-tidy raised.

The UX is terrible: for example there are no spinners or text boxes. However, somewhat artificially, I am happy to stick with 3 buttons and concentrate on the code style.

I am here to improve my JavaScript, jQuery and HTML style, so all comments welcome. I'd particularly welcome improvements to maintainability.

function addHandler () {
  console.log('Adding a widget to basket');
  widgetsInBasket += 1;
  updateWidgetBasket();
  tidyView();
}

function removeHandler () {
  if (widgetsInBasket >= 1) {
    console.log('Removing a widget from basket');
    widgetsInBasket -= 1;
    updateWidgetBasket();
  }
  if (widgetsInBasket < 1) {
    console.log('Widget basket is empty');
  }
  tidyView();
}

function emptyWidgetBasket () {
  widgetsInBasket = 0;
  $('#widget_basket').text(widgetsInBasket);
}

function buyHandler () {
  var widgetOrderQuantity;
  if (widgetsInBasket > 0 && widgetsInBasket <= widgetStock) {
    // assume delivery and payment details already registered
    widgetOrderQuantity = widgetsInBasket;
    console.log('Here I should submit an order for ' + widgetOrderQuantity + ' widgets');
    widgetStock -= widgetOrderQuantity;
    updateWidgetStock();
    $('#order_feedback').text('Processing your order for ' + widgetOrderQuantity + ' widgets');
    emptyWidgetBasket();
  }
  else {
    console.log('Unable to order widgets');
    // TODO: identify specific errors to user
    $('#order_feedback').text('Sorry, you cannot order ' + widgetsInBasket + ' widgets at this time');
  }
}

function updateWidgetBasket () {
  $('#widget_basket').text(widgetsInBasket);
}

function updateWidgetStock () {
  $('#widget_stock').text(widgetStock);
}

function tidyView () {
  $('#order_feedback').text('');
}

// main //
var widgetsInBasket = 0;
var widgetStock = 5;
$('#add_widget').click(addHandler);
$('#remove_widget').click(removeHandler);
$('#submit_order').click(buyHandler);
updateWidgetStock();
$('#widget_basket').text(widgetsInBasket);
<!DOCTYPE html>
<html>
    <head>
        <title>Widget Store</title>
        <script language="javascript" type="text/javascript"
                src="https://code.jquery.com/jquery-1.12.4.js">
        </script>
    </head>
    <body>
        <h2>Widgets in stock</h2>
        <p><span id="widget_stock">Loading</span> widgets</p>
        <h2>Your basket</h2>
        <p><span id="widget_basket">0</span> widgets</p>
        <p>
            <button id="add_widget">Add to basket</button>
            <button id="remove_widget">Remove from basket</button>
        </p>
        <p>
            <button id="submit_order">Submit order</button> <span id="order_feedback" />
        </p>
        <script language="javascript" type="text/javascript"
                src="store.js"></script>
    </body>
</html>

The only feature that I definitely want to add is payment information, in particular an Ethereum wallet address, so naturally I will try this and perhaps even post my own answer with my findings.

However, the main aim of code style is to help maintainers. So you could bear in mind these other possible future needs:

  1. better UX, such as a text input box, and diagnostic messaging to the user ("We don't have that many widgets in stock", "Your basket is empty")
  2. multiple products
  3. asynchronous order processing
  4. server-side stock control
  5. support more browsers, keyboards and touch devices
  6. unit tests
  7. include in a more complex or interesting web page

I am not asking how to build those things, but I'd like maintainers (or my future self) to be able to add those things without cursing me.

It only needs to run in my own browser, Chrome 60.

I chose jQuery 1.12 because it came with Ubuntu, and because it seemed easier to learn than the DOM API. I am open to recommedations of other frameworks, or even none. I don't mind using ES5 or ES6 features, or even ES2017: I only omitted a pre-processor because I don't need one yet.

I have a couple of global variables, because they are global in the document. However, if you think I should encapsulate them now (perhaps in objects or in closures) please tell me.

I didn't add data structure(s) to support multiple products, because YAGNI, and my opinion that it makes the code clearer and easier for me to concentrate on what I want to learn and simulate.

My simulation is similar in spirit to this question. It intentionally has fewer features than this question in Angular.JS, this one in React, and this closed question.

\$\endgroup\$
  • 1
    \$\begingroup\$ Make sure you're defining objects and these interact through functions, not through object properties directly. And that goes for trivial things too, for example a product object with a name and price (for now). Do not not define an object just because you need only 1 for this starter demo. Object-ify, encapsulate, expose the functionality, hide the properties. Given a radically changing UI, maybe have ShoppingCart functions for taking UI controls and wiring up event handlers. This general modularization embiggens unit testing. \$\endgroup\$ – radarbob Jul 30 '17 at 4:54
  • \$\begingroup\$ Thanks @radarbob. Your comment makes me suspect that my functions know too much about the document. Perhaps a ShoppingCart's initialization function could wire itself up to the browser events and elements? \$\endgroup\$ – dcorking Jul 30 '17 at 6:31
  • \$\begingroup\$ By initialization function, I think I mean constructor. Sorry. \$\endgroup\$ – dcorking Jul 30 '17 at 6:50

Your Answer

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

Browse other questions tagged or ask your own question.