===========
Form events
===========

We'll consider how form events are triggered on example of view forms. 
For forms of other types, events are triggered the same way.

After the form is created, and the form's html template have been added to the 
DOM, the application triggers the following events:

* :doc:`on_view_form_created </refs/client/task/on_view_form_created>`
  of the task, if one is defined. 
* :doc:`on_view_form_created </refs/client/group/on_view_form_created>`
  of the group that owners the item, if one is defined for the group.
* :doc:`on_view_form_created </refs/client/item/on_view_form_created>`
  of the item, if one is defined.
  
This way we can define a basic behavior for all items in the 
:doc:`on_view_form_created </refs/client/task/on_view_form_created>`
event handler of the task, that can be expanded in the event handler of the 
group, and finally, if nessesary, can be specified in the event handler of the 
item itself.
  
For example, the
:doc:`Demo project </intro/demo_project>` 
has the following event handler, 
defined in the client module of the task:

.. code-block:: js

    function on_view_form_created(item) {
        var table_options = {
                height: 580,
                sortable: true
            };
        if (item.view_form.hasClass('modal')) {
            item.view_options.width = 1060;
        }
        else {
            item.view_form.find(".modal-body").css('padding', 0);
            item.view_form.find("#title-text").text(item.item_caption)
            table_options.height = $(window).height() - $('body').height() - 20;
        }
        
        if (item.can_create()) {
            item.view_form.find("#new-btn").on('click.task', function() { item.insert_record(); });
        }
        else {
            item.view_form.find("#new-btn").prop("disabled", true);
        }
        
        item.view_form.find("#edit-btn").on('click.task', function() { item.edit_record() });
        
        if (item.can_delete()) {
            item.view_form.find("#delete-btn").on('click.task', function() { item.delete_record() } );
        }
        else {
            item.view_form.find("#delete-btn").prop("disabled", true);
        }

        item.paginate = true;        
        if (item.view_form.find(".view-table").length) {
            if (item.init_table) {
                item.init_table(item, table_options);
            }
            item.create_table(item.view_form.find(".view-table"), table_options);
            item.open(true);
        }
    }
    
This code is executed for every item, whose 
:doc:`view </refs/client/item/m_view>`
method was called. The item itself is passed as a parameter. The 
:doc:`view_form </refs/client/item/at_view_form>`
attribute is a JQuery object of the form’s html.

This event performs the following:

* Defines the options for a table that will be created later by 
  :doc:`create_table </refs/client/item/m_create_table>`
  method.

* Checks, if the form is modal, and sets the width of the modal form, using the 
  :doc:`view_options </refs/client/item/at_view_options>`
  attribute, see :doc:`Form options <form_options>` for details. For a modless 
  form it sets the title and calculates the height of the table, depending on 
  the height of the Web browser page.
  
* Uses JQuery to assign event handlers for the buttons, specified in the html 
  template of the form, to the methods of the item.
  
* Sets the 
  :doc:`paginate </refs/client/item/at_paginate>`
  atrribute to true, so the table will paginate the item’s 
  dataset. When this attribute is set, the table calculates the number of the 
  rows displayed, based on its height. The table will internally manipulate the 
  limit and offset parameters of the open method, depending on its height and 
  current page, reopening the dataset when needed.
  
* Checks if the div with 'view-table' class is defined if the view form html template,
  and if it exists, creates a table in this div using
  :doc:`create_table </refs/client/item/m_create_table>`
  method of the item. But before doing so, checks if the client 
  module of the item has init_table function, and if the init_table function is 
  defined, calls it, passing table_options as a parameter, see 
  :doc:`Working with modules </programming/modules>`.
  
* Executes open method, that sends a request to the server, that generates an sql
  query to the database
  
After the 
:doc:`on_view_form_created </refs/client/task/on_view_form_created>`
of the task is executed, the application triggers the 
:doc:`on_view_form_created </refs/client/group/on_view_form_created>`
event of the group that owns the item. So the
:doc:`default code </intro/default_code>` implements searching for catalogs
group and filters for journals. Developers can create their own groups and write 
code common for all items that these groups own.

And finally, the on_view_form_created of the item itself is triggered (if defined).

In the Demo, the client module of the "Customers" catalog has the following 
event handler, that assign JQuery events to "Email" and "Print" buttons:

.. code-block:: js

    function on_view_form_created(item) {
        if (!item.view_form.hasClass('modal')) {    
            item.view_form.find('#email-btn')
                .click(function() {
                    if (item.task.mail.can_create()) {
                        item.task.mail.open({open_empty: true});
                        item.task.mail.append_record();
                    }
                    else {
                        item.warning('You are not allowed to send emails.');
                    }
                })
                .show();
            item.view_form.find('#print-btn')
                .click(function() {
                    item.task.customers_report.customers.value = item.selections;
                    item.task.customers_report.print(false);
                })
                .show();
        }
    }


The same way the 

* ``on_view_form_shown``

* ``on_view_form_closed``

* ``on_view_form_keydown``

* ``on_view_form_keyup``

events are triggered. First for the task, then for the group and finally for 
the item.

The only exception is ``on_view_close_query`` event that is triggered by
:doc:`close_view_form </refs/client/item/m_close_view_form>` 
method.

The developer can use this method to close view form of an item. But it as well, 
called by an apllication when a user clicks on the close button of a modal 
form or an attempt is made to destroy a modeless form.

The 
:doc:`close_view_form </refs/client/item/m_close_view_form>`
method triggers on_view_form_close_query events in reverse order.

First, it triggers the item’s 
:doc:`on_view_form_close_query </refs/client/item/on_view_form_close_query>`
(if defined) event handler. If the event handler is defined and returns true - 
the form is destroyed, the item’s view_form atrribute is set to undefined and 
the methods exits, if it returns false - the operation is aborted and the 
methods exits.

If the item’s event handler don’t return a value (returns ``undefined``), the 
event handler of the item’s group is processed the same way, and after that the 
:doc:`on_view_form_close_query </refs/client/task/on_view_form_close_query>`
event handler of the task.

If no event handler is defined or none of these event handlers return false, the 
form is destroyed and the item’s view_form atrribute is set to undefined.

