add a repeated group with javascript

arie

Member
Hi,
I've added this piece of code in a x.js file in order to add a group by js but I've got an issue.

here is the code
Code:
function addGroup(formRef,groupId,repeatNum){
   
    var form = Fabrik.blocks[formRef];
    // Create mock event
    var btn = form.getElement('#group' + groupId + ' .addGroup');
    if (typeOf(btn) !== 'null') {
      var e = new Event.Mock(btn, 'click');
                       
      // Duplicate group
      for (var i = 1; i < repeatNum ; i ++) {
        form.duplicateGroup(e);
      }
    }
}

and here is the issue
Uncaught TypeError: Cannot call method 'getElement' of undefined

This issue comes form the line 5
Code:
var btn = form.getElement('#group' + groupId + ' .addGroup');


cheers
 
I think this will achieve the same result, in a more hacky-ish fashion:

Code:
var addGroup = function(group_id, repeat_num){
    while(repeat_num){
          repeat_num--;
          $(group_id).getElements('a.addGroup').getLast().click();
    }
};

It works (at least on my development site), but I'm not sure it's following current 'best practices'.

Now if the group element id you're passing doesn't match an element in the dom, this function will cause that same error, of course. So I'd check that first and foremost.
 
  • Like
Reactions: rob
The method in the OP should work, it's what we do in form.js when adding a set number of groups.

Can you give me a link to the form in question? I'll Firebug it ...

-- hugh
 
OK, the problem is that you are running your page load code before Fabrik has been initialized, so the form object hasn't been created yet. So when you do:

JavaScript:
var form = Fabrik.blocks[formRef];

... it's null.

Safest way is to wrap anything you want to do on load in a head.ready() call, so it delays running till head.js has finished loading and running all the required "stuff" ...

JavaScript:
head.ready(function() {
// Fabrik is available now, put your init code here.
});

-- hugh
 
ok this proved to be a simple first solution, but then to get what arie actaully needed its rather complicated, as he needed to duplicate a number of groups based on a querystring variable, and then set each cdd's value based on the same querystring value. The main issue being that its hard to know when the cdd has updated its options, and setting the value before the options are populated won't work, so this is what I came up with:

JavaScript:
// So that we only add groups once on page load
updated = false;

/**
 * Parse URL
 * 
 * @returns object
 */
function loadParams() {
    var params = {};
    if (location.search) {
        var parts = location.search.substring(1).split('&');
        for (var i = 0; i < parts.length; i++) {
            var nv = parts[i].split('=');
            if (!nv[0]) continue;
            params[nv[0]] = nv[1] || true;
        }
    }
    return params;
}

/**
 * Duplicate a group
 * 
 * [USER=20939]param[/USER] string  formRef  Form ref, e.g. 'fom_11'
 * [USER=20939]param[/USER] int     groupId  Group id to duplicate
 */
function addGroup(formRef, groupId) {
    var form = Fabrik.blocks[formRef];

    // Create mock event
    var btn = form.form.getElement('#group' + groupId + ' .addGroup');
    if (typeOf(btn) !== 'null') {
      var e = new Event.Mock(btn, 'click');
                        
      // Duplicate group
      form.duplicateGroup(e);
    }
}


/**
 * Watch cdd updates as this is the first time they will contain their options
 */ 
Fabrik.addEvent('fabrik.cdd.update', function (e) {
    
    var formRef = 'form_11';
    var elements = Fabrik.blocks[formRef].formElements;
    if (e.element.name.contains('ass_promesse_donation___promesse_id')) {
        
        var i, v, params = loadParams();
        if (params.promesses_id !== '') {
            var value = params.promesses_id.split(',');
            
            if (updated !== true) {
                
                // Set flag so this won't run again
                updated = true;
                
                // Add a group for each value, starting from the second value
                for (i = 1; i < value.length; i++) {
                    addGroup(formRef, 19);
                }
            }
        
            // Update values
            for (v = 0; v < value.length; v ++) {
                var el = elements.get('join___33___ass_promesse_donation___promesse_id_' + v);
                if (el) {
                    el.update(value[v]);
                    
                    // Odd spinner artifact that may need removing
                    var spinner = el.getContainer().getNext('.spinner'); 
                    if (spinner) {
                        spinner.destroy();
                    }
                }
            }
        }
    }
});

arie I've left your original 11.js file on the server and renamed it to 11_orig.js and have added 11.js with JUST the code I've pasted above. You may need to cherry pick what was into 11_orig.js to re-insert into the new 11.js.
 
We are in need of some funding.
More details.

Thank you.

Staff online

Members online

Back
Top