Form Javascript Objects

Jan 24, 2016
Form Javascript Objects

  • Introduction(top)

    The way form JS is handled has changed in Fabrik 3.x. To interact with a Fabrik form you now add event listeners in your custom Javascript files.

    Alternatively write your js inside your form templates.

    Form Events(top)

    When various actions are performed by a Fabrik form, it fires events (much in the same way that a mouse click broadcasts a mouse click event). You can then write JavaScript code to listen and run on the broadcast of these events:
    Code (Javascript):
    Fabrik.addEvent(eventName, function(form){
      // do your code here
    });
    Possible options for eventName (passed in variables shown in brackets)
    • fabrik.form.doelementfx (form)
    • fabrik.form.elements.added (elements) // All elements have been added to the form's formElements property
    • fabrik.form.groups.save (form)
    • fabrik.form.groups.save.start (form)
    • fabrik.form.groups.save.end (form, json)
    • fabrik.form.group.delete (form, event)
    • fabrik.form.group.delete.end (form, event, groupId, repeatCounter)
    • fabrik.form.group.duplicate (form, event)
    • fabrik.form.group.duplicate.end (form, event, groupId, repeatCounter)
    • fabrik.form.submit.start (form, event, button)
    • fabrik.form.submitted (form, json to update) - only called when form is saving using ajax
    • fabrik.form.submit.end (form)
    • fabrik.form.update (form, json)
    • fabrik.form.reset (form)
    • fabrik.form.delete (form, rowid)
    • fabrik.form.page.change (form, dir) - run when the next/previous button is pressed on a multipage form, before the page is changed. (dir option added 17/04/2015)
    • fabrik.form.page.change.end (form, dir) - run when the next/previous button is pressed on a multipage form, after the page is changed. (dir option added 17/04/2015)

    Group JS(top)

    To duplicate a forms repeating group a certain number of times:
    Code (Javascript):
    // Your form reference
    var formRef = 'form_2';

    // The group you wish to repeat's ID
    var groupId = 1;

    // The number of times to repeat

    var repeatNum  = 3;
    var form = Fabrik.blocks[formRef];

    // Get the repeat group button
    var btn = form.getElement('#group' + groupId + ' .addGroup');
    if (typeOf(btn) !== 'null') {

      // Create mock event
      var e = new Event.Mock(btn, 'click');
       
      // Duplicate group
      for (var i = 1; i < repeatNum ; i ++) {
        form.duplicateGroup(e);
      }
    }

    Examples (top)

    Stop current method from continuing (top)

    To stop the form from continuing its current method set the form's result property to false:
    Code (Javascript):
    Fabrik.addEvent('fabrik.form.submit.start', function(form, event, button) {
        alert('aha! you really should not press that button');
        form.result = false;
    })

    Prevent form deleting (top)

    To stop the form from deleting:
    Code (Javascript):
    Fabrik.addEvent('fabrik.form.delete', function (form, rowid) {
        return false;
    });
    // If you don't return false then the fabrik.form.submit event will be fired

    Setting end date 2 hours after the start date (top)

    See this mootools documentation page for more info on altering dates in Javascript.

    Apply this code to a change event on your start date element. When it's value is changed the end date's value will be set to the start dates value plus 2 hours
    Code (Javascript):
    // Alter formRef and endDate to match your form's id and the end date element's full name:
    var formRef = 'form_1';
    var endDate = 'tablename___end_date';
    var end = Fabrik.blocks[formRef].formElements.get(endDate);
    var newDate = new Date(this.get('value'));
    newDate.increment('hour', 2);
    end.update(newDate);

    Copying values from details view to a form(top)

    See this thread for an intro
    Code (Javascript):
    // Alter the 1 & 2 to match you form ids.
    var detailsRef = 'details_1';
    var formRef = 'form_2';

    Fabrik.addEvent('fabrik.form.elements.added', function (block) {

      // Ensure that both the form and details view have loaded
      if (Object.getLength(Fabrik.blocks) === 2) {

        // Copy the line below and alter for each element you want to update
        copyFromDetails('userlist___name', 'tasks___username');
        copyFromDetails('userlist___surname', 'tasks___surname');
      }
    });

    function copyFromDetails(from, to) {
      // Get the details view and elements:
      var fromElements = Fabrik.blocks[detailsRef].formElements;

      // Get the form and its elements
      var toElements = Fabrik.blocks[formRef].formElements;

      // Get details value
      var fromValue = fromElements.get(from).get('value');

      // Update form element with value.
      taskElements.get(to).update(fromValue);
    }

    Updating an element with the difference between two date elements (top)

    See here for an intro

    Say your form has an id of 1. Create a file components/com_fabrik/js/form_1.js

    And that you have 3 elements:

    2 dates whose full names are 'tablename___date1' and 'tablename___date2' from which you want to calculate the difference.

    And a third to show the difference, 'tablename__output'

    Enter this in the js file you created above:
    Code (Javascript):
    Fabrik.addEvent('fabrik.form.elements.added', function () {
        // All the elements have been loaded in Fabrik
        var form = Fabrik.blocks.form_1; // Replace 1 with your form id

        var elements = form.formElements;
        var date1 = elements.get('tablename___date1');
        var date2 = elements.get('tablename___date2');

        var output = elements.get('tablename___output');

        // A function to work out the date difference
        var doDiff = function () {
            // Create two JS date objects
            var d1 = new Date.parse(date1.get('value'));
            var d2 = new Date.parse(date2.get('value'));

            // diff in miliseconds
            var diff = d1 - d2;
            var dayDiff = diff / (24 * 60 * 60 * 10 * 10 * 10);

            // Update the output element with the number of days
            output.update(dayDiff);
        }

        // Add events to the two dates to work out the date difference
        date1.addNewEvent('change', function (e) {
            doDiff();
        });

        date2.addNewEvent('change', function (e) {
            doDiff();
        });

    })

    Updating an date element with the current time when its group is repeated (top)

    Code (Javascript):
    Fabrik.addEvent('fabrik.form.group.duplicate.end', function (form, event) {

      // Replace 204 with the repeat group's id
      var groupId = 204;

      // Get the number of times the group has been repeated
      var repeatMax = form.repeatGroupMarkers[groupId];

      // Get the newly added element
      var el = form.formElements['join___131___tablename___elementname_' + repeatMax];

      // Update the element with the current date/time
      el.update(new Date());
    });

    Hide / Show an element located in more than one repeating group (top)

    Code (Javascript):
    // replace 1 with the form's id
    var formRef = 'form_1';

    // Replace with the element name (note it is prefixed with join___JOINID___)
    var elementName = 'join___131___regons___country_id';

    // Get the form's elements
    var elements = Fabrik.blocks[formRef].formElements;

    // Filter the form's elements to get every repeating instance of the element
    var f = elements.filter(function (element, key) {
        return key.contains(elementName);
    });

    // Loop over each element to hide it
    f.each(function(r) {
        r.getContainer().hide();
    });

    // OR loop over each element to show it
    // Loop over each element to hide it
    f.each(function(r) {
        r.getContainer().show();
    });

    Total line items and update total element in another group (top)

    Code (Javascript):

    requirejs(['fab/fabrik'], function () {
    function total() {
      // replace 1 with the form's id
      var formRef = 'form_34';

      // Replace with the element name
      var elementName = 'quote_items___unit_price';

      // The element containing the line items total
      var totalElement = 'quotes___inv_total';

      var total = 0;

      // Get the form's elements
      var elements = Fabrik.blocks[formRef].formElements,
      v;

      // Loop over the elements and if their key contains the elementName update the total
      elements.each(function (element, key) {

          if (key.contains(elementName)) {
          v = element.get('value').toFloat();
          if (typeOf(v) !== 'null') {
          total += v;
          }
          }
      });



      // update the total element
      elements.get(totalElement).update(total);
    }

    // Add events when adding/deleting groups
    Fabrik.addEvent('fabrik.form.group.duplicate.end', function (form, event) {
      total();
    });

    Fabrik.addEvent('fabrik.form.group.delete.end', function (form, event) {
      total();
    });

    document.addEvent('blur:relay(input[name^=quote_items___unit_price])', function () {
    total();
    })
    })
     

    Exclusive Select Dropdowns(top)


    Sometimes you may want to have "exclusive selection" on multiple instance of the same dropdown, whereby you only allow any given option to be selected in one of them. For example, you might be booking classes, for morning and afternoon, and you have two join elements to your "courses" table, and if they select "English" for the morning, you don't want them to be able to select it for the afternoon.

    To achieve this, you would put this in your form_X.js file ...

    Code (Text):

    function doCourses(el) {
        /*
          * els is an array of the full element names of all the dropdowns
         * you want to apply the 'exclusive selection' to, and is the only thing you need to change
         */
        var els = ['fab_lesson_bookings___morning', 'fab_lesson_bookings___afternoon'];
        els.each(function (dd) {
            if (dd != el.element.id) {
                thisel = el.form.formElements.get(dd).element;
                jQuery(thisel.options).prop('disabled','');
                thisel.options[el.element.selectedIndex].disabled="disabled"
            }
        }.bind(el));
    }
     
    Then on your two join elements, you would add a JavaScript event, on 'click', with the code ...

    Code (Text):

    doCourses(this);
     
    Simply replace the full element names in the 'els' array with the full element names of your elements, which could be regular dropdowns, or joins set to dropdown. The only caveat as that they need to be dientical, with the same options in the same order. You can have any number, the example just uses two.

    List Events(top)

    For List javascript events -> go here
davez and xfabiox like this.