Bakery Tutorial

This is part of a tutorial series that shows how to build a data-driven web application using Visual Studio Code, ASP.NET Core Razor Pages, Entity Framework Core and SQLite and .NET 7.

The source code for the completed application is available on GitHub

Adding TypeScript Support

In this section, you will learn how to add support for TypeScript to your Razor Pages application. Similar to Sass a couple of sections ago, TypeScript is not essential for working with client-side code, but it is a great productivity assistant. And, like Sass, TypeScript code is not used by your application directly. It is compiled to JavaScript. Your application will work with the resulting .js files that are generated by the TypeScript compiler.

So why use TypeScript instead of writing JavaScript directly?

TypeScript is a superset of JavaScript that adds static typing to the language. This means that TypeScript code can be checked for type errors at compile time, which can help to prevent runtime errors. TypeScript also provides other features that can make browser-based JavaScript development more reliable and efficient, such as:

  • Interfaces: Interfaces can be used to define the shape of data structures, which can help to prevent errors when passing data between different parts of an application.
  • Generics: Generics can be used to create reusable code that can work with different types of data.
  • Modules: Modules can be used to organize code into logical units, which can make it easier to understand and maintain large codebases.

If you are new to TypeScript, I recommend you visit the official site for more guidance.

In this section, you will configure TypeScript in your application, and then use it to generate a small amount of JavaScript code that will calculate the total price of an order prior to the user submitting the form.

To begin, you need to install TypeScript itself if you haven't already done so at some point. This can be done via the Node Package Manager (npm) which is enabled by default in VS Code.

Open a terminal and execute the following command, which will install the latest version of TypeScript globally:

npm install -g typescript

Next, you need to configure the TypeScript compiler's behaviour within your application. Configuration is specified in a tsconfig.json file, which you create by executing the following command:

tsc --init

The resulting file contains a default configuration which is sufficient for your needs for this exercise. If you want to take advantage of modules that use import and export, you should change the target and module options to "ES2020" at least. To support the latest features regardless of version, you can change these options to "ESNext".

Now you will modify the Order page to include a hidden field for the unit price of the item being ordered, and some elements to act as containers for the result of the calculation. Add the highlighted lines just before the exising button:

<form class="col-9" method="post">
  <div class="form-group mb-3">
    <label asp-for="Quantity" class="form-label"></label>
    <input asp-for="Quantity" class="form-control" /> 
    <span asp-validation-for="Quantity"></span>
  </div>
  <div class="form-group mb-3">
    <label asp-for="OrderEmail" class="form-label"></label>
    <input asp-for="OrderEmail" class="form-control " />
    <span asp-validation-for="OrderEmail"></span>
  </div>
  <div class="form-group mb-3">
    <label asp-for="ShippingAddress" class="form-label"></label>
    <textarea asp-for="ShippingAddress" class="form-control"></textarea>
    <span asp-validation-for="ShippingAddress"></span>
  </div>
  <input type="hidden" asp-for="UnitPrice" value="@Model.Product.Price"/>
  <div class="mb-3"> Total cost: <span id="orderTotal">@Model.Product.Price.ToString("c")</span></div>
  <button type="submit" class="btn bn-sm btn-primary">Place order</button>
</form>

Next, add a new file to the wwwrooot/js folder named order.ts with the following content, which uses standard DOM APIs to reference the quantity and unit prices along with the span you just added for the order total. It listens for the change event of the Quantity input and calculates the total price for the order based on the quantity specified, outputting the result ot the span:

const unitPriceElement = document.querySelector('#UnitPrice') as HTMLInputElement;
const quantityElement = document.querySelector('#Quantity') as HTMLInputElement;
const orderTotalElement = document.querySelector('#orderTotal') as HTMLSpanElement;
if(quantityElement && unitPriceElement && orderTotalElement){
    quantityElement.addEventListener('change', _ => {
        const unitPrice = Number(unitPriceElement.value);
        const quantity = Number(quantityElement.value);
        const orderTotal = unitPrice * quantity;
        orderTotalElement.textContent = orderTotal.toLocaleString('en-GB', {
            style: 'currency',
            currency: 'GBP',
        });
    });
}

You may want to change the locale and currency settings passed to the Number.toLocaleString function to support your culture.

Note

The DOM elements are cast to their specific type using the as keyword, so that the value property can be accessed. Without this casting, the types returned from the querySelector method would be Element, which only exposes those properties and methods that are common to all document elements.

Rather than manually compiling your TypeScript files every time you change one, you can initiate a TypeScript compiler process that continuously monitors files for changes. Whenever a file is modified, added, or deleted within the application, the TypeScript compiler recompiles the modified files and any dependent files. This process is initiated by executing the following command:

tsc --watch

Having executed this command, you should find that a new file has been added to the wwwroot/js folder - order.js. This is the output generated by the TypeScript compiler from the file you just authored. In this example, you should notice that the content of the generated JavaScript file is almost identical to the TypeScript version, with the type assertions removed.

Reference the file in the scripts section of the Order page as follows, using the script taghelper with the append-version attribute set to true which will ensure that the latest version will always be downloaded to the client:

@section scripts{
    <partial name="_ValidationScriptsPartial" />
    <script src="~/js/order.js" asp-append-version="true"></script>
}

Then change the quantity value and check that the order total is updated:

JS updating the order total

Summary

In this section, you learned how to configure TypeScript in the application to manage your JavaScript files, then you added some logic to calcuate the total cost of the order interactively. At the moment, the user can only order one item at a time. In the next section, you will add a cookie-enabled shopping basket facility that tracks multiple orders for the user.

Last updated: 12/3/2024 8:22:19 AM

© 2018 - 2024 - Mike Brind.
All rights reserved.
Contact me at Mike dot Brind at Outlook.com