Book Image

KnockoutJS Blueprints

By : Carlo Russo
Book Image

KnockoutJS Blueprints

By: Carlo Russo

Overview of this book

Table of Contents (12 chapters)
KnockoutJS Blueprints
About the Author
About the Reviewers

Contact form

Our friends asked us if we could add a way to pay from the website. We can do it for sure, but it involves code in the backend.

For this first project, we are not going to write any code for the backend, so we will not implement this functionality; we will try to keep the flow simple, so we will open the default mail program with pre-configured text.

Paying from the client-side code

If you are thinking, why do I need a backend code to manage all of this? I have seen on the PayPal website that I can send a payment request using only JavaScript, let's wait a moment and read this hint:

Never use a Javascript-only solution to manage money.

Have you heard about XSS, CSRF, and the other threats you can face with website programming?

You can find many good resources about these threats, and I suggest you research them (any good web developer should know about security).

I'll just explain the simpler reason here. JavaScript is a client-side language; it runs within the browser, so any one can hack it easily.

Let's try to imagine this scenario:

A customer puts in his cart three products that are worth £60. Then, he (he's smart, isn't he?) opens the developer console and updates the localStorage, setting all the prices to negative value. Next, he navigates to the contact page, and we ask him to use PayPal to pay -£60.

What happens here? It depends on PayPal, or on the payment system you are trying to implement.

In the best case, it stops the transaction (but what if the customer puts £0?). In the worst case, it could grab the money from your account to give it to the customer.

If the system blocks a negative transaction, it can change all the prices to £0 (or £0.01 if it wants to be sure that everything works). The system will accept the transaction, and your friends will get a notification that they have to send a few products to someone without being paid.

So, try to remember that client-side validation is helpful to improve performance and give the user a better experience. But at the end of the day, any data you have to save on a database has to be checked on the server side.

The contact form

We are going to realize a small contact form to send to our friends a mail with the list of products the customer wants to buy.

We cannot send email using only JavaScript, so for this first chapter, we will build the mail body inside our page, and then use the mailTo: URL to ask the system to open the preferred mail application with the data we collected.

The customers can fill their email address and the body of the mail, and we will add to the mail the list of the products he wants to buy.

This page will be similar to the cart page, because we will show a list of all selected products. But here, we will not give the user a way to remove the item; we will give him a way to send the email with the items.

This time we will start with the HTML of the Cart View, and then modify it; copy cart.html into contact_us.html.


Best practices with programming tell us that copying and pasting code is never a good thing; maybe it's an easy way to solve a problem, but then you can make the maintenance hell.

For this reason, when you see you have to put the same code in more than one place, with only small modifications, try to change the structure, use the inheritance or the composition, and avoid copy and paste!

The only time you cannot do this easily is with HTML, because if you load the markup from an external template with jQuery, you face problems with binding and so on.

In the next chapter, we will use the template and the component binding handler, and we will find how to solve the copy-paste problem in HTML.


  • Update the title to Jewelry Show Case – Contact

  • Remove the H1: <h1>Here you can find all the items in the cart.</h1>

  • Add the form to get the email address and a message; wrap the entire block <div data-bind="foreach: products"> in this way:

    <form data-bind="submit: buy">
      <div class="field">
        My mail address:
        <input type="text" data-bind="textInput: email"/>
      <div class="field">
        Additional details:
        <textarea data-bind="value: message"></textarea>
      <h1>List of items I would like to buy</h1>
      <div data-bind="foreach: products"></div>
      <div class="clear-float"></div>
      <input type="submit" value="Send the buying message"
             data-bind="enable: canBuy"/>
  • We don't want to give the user a way to remove a product here, so remove from the product box the button, <button data-bind="click: $root.removeFromCart">Remove from the cart</button>

  • Update the script tag <script type="text/javascript" src="js/cart.js"></script> with the new script name <script type="text/javascript" src="js/ contact_us.js "></script>

Let's better analyze the important markup (where we put binding) here:

<form data-bind="submit: buy">

In this way, we are putting all the data inside a form, and we will execute the buy function when the user submits the form (either by clicking on the submit button or using the enter key).

<input type="text" data-bind="textInput: email" />

We are using again the textInput binding handler because we want to react immediately to the field changes.

<textarea data-bind="value: message"></textarea>

We are using the value binding handler here for the message because we are not putting any additional logic based on the value of that field.

<input type="submit" value="Send the buying message" 
                     data-bind="enable: canBuy"/>

We are adding the enable binding handler to enable/disable the submit button, to be sure that the user has to fill the required email field before trying to send the email.


In this case, the only difference between the submit binding handler and the click binding handler attached to this button is that you can press enter when you are in the email field and the form will be submitted.

Obviously, is important to understand when it is better to use one and when the other, depending on the specific context you are working on.

Now, we can work on the Cart View Model (js/cart.js).

This View Model will begin similarly to the Cart View Model because we need to fetch the product list and show the products we have in the basket.

Then, we will add the specific code: two observables, a computed observable, and a function:

var myViewModel = {
  basket: new Basket(),
  email: ko.observable(""),
  message: ko.observable(""),
  buy: function() { /* CODE TO SEND THE EMAIL */ }
myViewModel.products = myViewModel.basket.products;
myViewModel.canBuy = ko.computed(function() {
  return &&

The canBuy computed observable checks that the email is not empty and that the cart contains at least one item.

Let's check the code of the buy function:

buy: function() {
  var productList = 
    ko.utils.arrayMap(myViewModel.products(),function(p) {
      return p.title;
  var additionalMessage = myViewModel.message() && (
      "This is an additional message I want to send you: \n\t" +
  var body = "Hi, I'm " + + 
             " and I want to buy these products from you.\n" +
             productList + "\n" +
  var mail = "mailto:[email protected]?" +
             "subject=" + encodeURIComponent("I want to buy these items") +
             "&body=" + encodeURIComponent(body);
  window.location.href = mail;

Here, we are taking the name of each product we have in the cart, the message, and the email, and putting it into an encoded string. We must encode it because otherwise we cannot use it inside a URL.

Then, we will use this string with the protocol, mailto, and update the current URL with this new one.

When we do this, the browser will try to open the default mail program to send this email.

Now, the Contact Us page is complete and you can use it to create the email with the messages and the products you want to buy.

If you have done everything like I have suggested, this is what you should get when you put three products in the cart and you are ready to send the mail:

And this is what we get after we click on the button (having Gmail registered as the default mail system, with Chrome in Windows):

Here, it opens Gmail with the information we entered in the form, as we expected.