Tutorial Step 2 - Adding New Items

Our goal in this step is to create a simple, web form based panel for adding new items to the shop.

Form generator

In the previous tutorial step, before we could browse the service content, we had to add some items manually, using Erlang shell. It could be easily done by passing a ready-to-use record to the wtype_item:create/1 function. Unfortunately, it can't be done in this way - we have to provide user some way to enter the data in its browser and send it to the server.

So far, we did not even touch item_types record. Right now, Erlang Web's form generator will use it for automatic form building process.

At first we should add rules to the dispatcher (put them right after the /item/show/N rule):

   1 {static, "^/item/add$", "item/add.html"}.
   2 {dynamic, "^/item/do_add$", {item_admin, do_add}}.

The first rule is responsible for displaying the form for our item. The second one will deal with actual item creation - will be associated with submit button placed on the generated form.

Look at the templates/item/add.html template:

<html>
<head>
  <title>Adding new item</title>
</head>
<body>
  <h1>Adding new item</h1>
  <wpart:form type="item" action="/item/do_add" />
</body>
</html>

wpart:form is responsible for the form building and is fully described here.

And the result (http://localhost:8080/item/add):

new_item_no_desc.png

Hmm, it seems that everything works correctly, but... We have completely no clue what is the meaning of the particular fields!

Adding the fields description and comments

Let's then edit the item_types record definition:

   1 -record(item_types, {
   2           id = {integer, [primary_key, {private, true}]},
   3           name = {string, [{description, "Name"},
   4                            {max_length, 256}]},
   5           description = {text, [{description, "Description"},
   6                                 {max_length, 10000}]},
   7           price = {float, [{description, "Unit price"},
   8                            {min, 0.0}]},
   9           available = {enum, [{description, "Is item available?"},
  10                               {choices, "true:Yes|false:No"}, 
  11                               {chosen, "true"}]}
  12          }).

new_item_no_comm.png

Much better! But user still does not know about the limitations for the particular fields - we should inform him about the constraints:

   1 -record(item_types, {
   2           id = {integer, [primary_key, {private, true}]},
   3           name = {string, [{description, "Name"},
   4                            {comment, "Maximum length is 256 characters"},
   5                            {max_length, 256}]},
   6           description = {text, [{description, "Description"},
   7                                 {comment, "Maximum length is 10000 characters"},
   8                                 {max_length, 10000}]},
   9           price = {float, [{description, "Unit price"},
  10                            {min, 0.0}]},
  11           available = {enum, [{description, "Is item available?"},
  12                               {choices, "true:Yes|false:No"}, 
  13                               {chosen, "true"}]}
  14          }).

new_item_no_css.png

Wonderful! But ugly as well - we should definitely start playing with CSS file!

Modifying CSS file

Erlang Web form generator uses some pre-defined HTML classes for the particular field types:

Let's create the CSS file (docroot/style.css):

.form_container {
    position: relative;
    width: 80%;
}

.form_entry
{
    margin-top: 25px;
    margin-left: 20px;
    position: inherit;
}

.form_input {
    position: absolute;
    left: 40%
}

.form_comment {
    position: absolute;
    top: 17px;
    left: 0;
    font-size: small;
    font-style: italic;
}

.form_error {
    font-variant: small-caps;
    color: red;
}

div#item_description, div#item_available
{
    margin-bottom: 40px;
}

Then we should add a proper entry to the dispatcher configuration file:

   1 {static, "^/style\.css$", enoent}.

And at the end edit the item/add.html template (add this line to the head section of the template):

<link rel="stylesheet" type="text/css" href="/style.css" />

That's all: refresh the browser and see how does it look:

new_item_final.png

Saving the data to the database

Ok, we are now ready with our form, we should now focus on the most important thing - saving the elements to the database. As we could see in the code above, dispatcher points to the item_admin:do_add/1 function as a handler for the /item/do_add request. We will use Erlang Web's generator once again:

$ ./bin/generate.erl controller --app shop --name item_admin 
Exported functions (separated with ,): do_add
File (...)/lib/shop-0.1/src/item_admin.erl created successfully!

And the result:

   1 -module(item_admin).
   2 -export([do_add/1]).
   3 
   4 do_add(_Args) ->
   5 %% put the do_add function body here
   6     ok.

Let's write some code then:

   1 do_add(_Args) ->
   2     case validate_tool:validate_cu(item, create) of
   3         {ok, Item} ->
   4             wtype_item:create(Item),
   5             {redirect, "/item/all"};
   6         {error, _Reason} ->
   7             wpart:fset("__edit", wtype_item:prepare_validated()),
   8             {template, "item/add.html"}
   9     end.

Remember that we can never trust the data that is not validated: in order to check if all the constraints are satisfied, we are calling validate_tool:validate_cu/2. It should either return us a message that the entered data is correct or an error. In case when everything is all right we will simply save the content to the database and redirect user to /item/all URL. Otherwise, we should go back to the form, but with some fields filled and the error messages set.

If everything is all right, after entering a correct data into form:

correct_form.png

we should be redirected to the /item/all and see one more item:

correct_all.png

When we click on the new item, we should see:

correct_details.png

Great! But what is going on when we enter the incorrect data?

incorrect_form.png

Hit the submit button and see the result:

incorrect_error.png

The error messages are surrounded with the span tags with class set to form_error. The messages are held inside the config/errors_description.conf. If you don't like the default ones you can change them easily.

Correct the data, hit submit and enjoy the new items in your shop!

Download

This tutorial step is over, the package containing the sources of the application can be downloaded from here.

Tutorial/Step2_FormBuilder (last edited 2010-03-22 12:39:23 by Michal Ptaszek)