Form Javascript driving me mad :(

rrwilson

Member
Hi there,

I dip my toe in and out of Fabrik every so often. I love it, but there is one topic that drives me potty - JS addressing/changing/accessing fabrik elements. I usually work my way through forum posts and get it to work eventually (or give up and make a nasty crosscutting calc element mess instead :p). It is probably my ignorance, but I find the docs very tricky on the topic of JS addressing fabrik elements, whether it is a new or editing form record, etc. .

I have an onchange element event that triggers the below inline JS, that roughly does this:
  • It is meant to read itself (i.e. the label for the selected databasejoin value) to see what the selected category is.
  • If that category is a certain value, then the JS is meant to then create a new row/group in a repeating group.
    • It is just a list of attribute names and their attribute value, e.g. Size and 1litre in one row/record/group - I am not sure of the correct Fabrik term).
    • This group is happily working on the form manually with only these two elements showing and the joining pk hidden.
  • Based on the category, the JS should then populate the attribute name and value elements in the repeated groups with specific strings.
    • I've been assuming that the joining primary key will just be autocompleted by fabrik in the same way as it is when manually adding repeat group rows
  • I have slapped this all into functions, but that doesn't seem to the issue.
It's going wrong re form/element addressing, as I am getting a "Cannot read property, undefined, etc." type console error. I have various console debug points throughout the script and see where it dies. I also have noted my attempts to deal with the rowid in the comments - I need to make it work on editing forms as well as adding. That is one of my 'losing it at fabrik js' topics.

Muchos thankos, I am really going mad over this one :)

RW.

JavaScript:
console.log('started');
   
function addnewgrouprows(formRef,groupId, repeatNum) {
  console.log('got to addnewgrouprows func');
  console.log('formRef ' + formRef);
  var form = Fabrik.getBlock[formRef];
  console.log('form ' + form);
  /* above debug shows form undefined here :( */
  /* Get the number of times the group has been repeated*/
  var repeatMax = form.repeatGroupMarkers[groupId];
  /* so it understandably dies here with "Cannot read property 'repeatGroupMarkers' of undefined"/*
  console.log('repeatMax ' + repeatMax);
  return repeatMax;
}

function newattribute(thisform,grouptochange,newrowname_element,new_prod_attrname,newrowvalue_element,new_prod_attrvalue){
  console.log('got to newattribute func');
  var rowid = addnewgrouprows(thisform,grouptochange,1);
  /* Get the newly added element - attribute name*/
  var prod_attr_name = form.formElements[newrowname_element + rowid];
  /* Update the element - attribute name*/
  prod_attr_name.update(new String(new_prod_attrname));
  /* Get the newly added element - attribute value*/
  var prod_attr_value = form.formElements[newrowvalue_element + rowid];
  /* Update the element - attribute value*/
  prod_attr_value.update(new String(new_prod_attrvalue));
}

/*get category and create relevant attribute*/
var list = 'Frontend_SKUs';
var $categoryID = $(list+'___Category');
console.log('debug $categoryID ' + $categoryID);

var category = $categoryID.textContent || $categoryID.innerText;
var category = $categoryID.value;
console.log(category);
console.log('debug category ' + category);
category = $categoryID[$categoryID.selectedIndex].innerHTML;
console.log('debug category again ' + category);
console.log(category);

var thisform='form_20';
console.log('debug thisform 1st ' + thisform);
/* tried two versions of getting rowid - based on wiki it seems to be necessary to allow add AND edit of new form records. But of a bit of a nightmare, read so many posts but still not clear*/
var myrowid = thisform + '.formElements.get(' + list +'___id).getValue()';
var myrowid = 'formElements.get(' + list +'___id).getValue()';
/* neither of above two work */
var thisform= thisform + '_' + myrowid;
console.log('debug thisform 2nd ' + thisform);
console.log(thisform);
var grouptochange=37;
var numnewrows=1;
var newrowname_element='Frontend_SKU_Attribute_Mapping___Attribute_';
var newrowvalue_element='Frontend_SKU_Attribute_Mapping___Value';

if (category.includes("Food")) {
    console.log('Food found');
    newattribute(thisform,grouptochange,newrowname_element,"Food",newrowvalue_element,category);
} else if (category.includes("Gifts")) {
    newattribute(thisform,grouptochange,newrowname_element,"Gifts for her",newrowvalue_element,category);
    newattribute(thisform,grouptochange,newrowname_element,"Gifts for him",newrowvalue_element,category);
    console.log('Gifts found');
} else if (category.includes("Beverage")) {
    newattribute(thisform,grouptochange,newrowname_element,"ABV",newrowvalue_element,category);
    console.log('Beverage found');
}



console.log('js end');
 
Yeah, I see a lot of problems in there. It basically needs to be re-written entirely from scratch.

What you are trying to do is not entirely trivial (my code phrase for "not easy"), especially if you aren't a reasonably proficient JS coder, with specific knowledge of how Fabrik does things.

And it's a little beyond what we can offer as part of subscription support.

So I can either offer some advice and pointers, or just quote you to write the code for you.

First advice. Don't do this "in line". Put your code in a function in ./components/com_fabrik/js/form_20.js, and call that function from the 'change' event of your element, passing 'this' (a reference to the Fabrik element object) as an object.

Code:
doAddProductGroup(this);

... then in your form_20.js ...

Code:
function doAddproductGroup(el) {
   // ... code goes here ...
}

That way you can actually debug it. Put breakpoints in it, step through code, try code out in the console, check what variables are set to, etc.

To make you life slightly easier, I just added a new function in the form JS to help with adding a group.

https://github.com/Fabrik/fabrik/commit/d8fc83086fa749168ece456bfeb36c8accb2c081

So with your function ...

Code:
   el.form.mockDuplicateGroup('37');

... will add a new repeat of that group. To find out what repeat instance was added, you can do ...

Code:
   var repeatCount = el.form.repeatGroupMarkers.get('37') - 1;

... note that as group ID's actually number from 0, you have to take 1 off that to get the ID suffix for elements you want to change.

To then set a value for one of the elements in that group ...

Code:
   el.form.formElements.get('Frontend_SKU_Attribute_Mapping___Value_' + repeatCount).update("new value");

-- hugh
 
PS, if you don't feel like doing a github update, you can look at what that code I added does, to simulate a click on the "Add" group button, and just do that.

Code:
var add_btn = el.form.form.getElement('#group37 .addGroup');
var add_e = new Event.Mock(add_btn, 'click');
el.form.duplicateGroup(add_e, false);

-- hugh
 
Hey there,

Thanks for the great advice and what you did. It looks do'able, but me slower than you... I would be interested in know in knowing how much it would be for you to code this for me (?).
 
Hey RW,

I'll need to do this work on your site. Can you fill out http://fabrikar.com/you/my-sites with the backend details, and put in the notes which form / element this is on. I'll also need either exTplorer installed, or ftp credentials, so I can create and edit the JS file.

-- hugh
 
For some reason I didn't see your post from Friday, or I'd have done this over the weekend. I'll do it today, when I've finished my first pass through the forums.

-- hugh
 
OK, question ...

In your original code you are trying to set the repeat group's 'value' (Attribute) to the specified string ("Gifts for her" etc). But that's a database join to another table, where those names don't seem to exist?

-- hugh
 
Hi there, completely true - I didn't think of that. It's a fresh spun VM and was easier with just the DB schema structures.

Any values will do actually, as long as they reference the correct tables. Call them anything you like, preferably something amusing :)
 
So is the assumption that there will be an entry in Frontend_SKU_Attributes (the table the Attribute element joins to) which matches those names you are creating? And you need to use the "label", not the "value" to set that join?

I'm a little confused.

-- hugh
 
Hi there, I have inserted an SKU at /manager/skus/form/20/2092 along with its associated category and attributes. But now you will see how it ties together from the Fabrik frontend. At the Mysql level there are foreign keys setup that tie it together, which is reflected in the working (and separate) databasejoin and repeating group logic. That logic should be a bit clearer now those records are there to see.

It works like this:
  • the Frontend_SKUs table record of a stock item gets its possible freetext categories from the Frontend_Categories table, storing only the raw id itself.
    • Frontend_SKUs.Category = Frontend_Categories.id
  • SKUS in Frontend_SKUs have their attributes shown in that repeating group, and those chosen attributes are stored in Frontend_SKU_Attribute_Mapping.
    • Frontend_SKUs.SKU = Frontend_SKU_Attribute_Mapping.SKU
    • So an stock item can have multiple attributes, like color and size
  • And the possible attributes to map to are stored in Frontend_SKU_Attributes, with Frontend_SKU_Attribute_Mapping only storing the raw id and getting the freetext attribute name from Frontend_SKU_Attributes
    • Frontend_SKU_Attribute_Mapping.Attribute = Frontend_SKU_Attributes.id
:cool:
 
That's the problem with complex database setups. Trying to describe them to someone else is like trying to describe a Mozart concerto in words.

But that still doesn't (as far as I can tell) answer my question.

In this code, you are wanting for a category name that contains (for example) "Gifts" to automatically add the Frontend_SKU_Attributes in the map table for "Gifts for her" and "Gifts for him". But even after you've entered data into that table, those don't exist.

So my confusion is to whether you were just using examples in your original code which you haven't entered into the Frontend_SKU_Attributes yet, or whether this script is supposed to create those, as well as adding the mappings for them.

-- hugh
 
Ahaaaa....I got you. Yup, those are just examples. You can just use add attributes a and b to the mapping table if category = x. with an 'else' to add just d attribute if category = y for example. The actual values of the attribute are the endusers choice :)

Makes sense?

(Good analogy re Mozart. Not quite as a sophisticated (although maybe Phil C did use the golden section too), but computing often feels like this to me:
)
 
OK, I'm still not getting it.

Your code specifically adds certain attributes, if the category contains certain strings.

The ones used in your code don't exist in the attributes table.

Should they exist?

We can't add new attributes to the Frontend_SKU_Attributes table programmatically from here. They can be added through the "Front end add" feature of the database join element, but that can't be driven through JS.

-- hugh
 
Nope they don't need to exist. They are just examples. And no need to add programmatically. You can add category Hugh and attribute grits if you like, and whenever an SKU record has its category set to Hugh an attribute of grits without a value will be created.

It's the code logic that counts, rather than what the category or attribute is.

Does that help? Late here and typinf on phone so hope I'm cogent....
 
Just reread this. I meant the example of the category Hugh resulting in addition of a mapped attribure to the attribute grits, but without a value being set.
 
We are in need of some funding.
More details.

Thank you.

Members online

Back
Top