Nested editing for additional fields on Mjoin link table
Nested editing for additional fields on Mjoin link table
Hi! I'm facing some difficulty with Editor.
A piece of my CRUD app have a N:M relationship between two tables: products
[prodotti] and accessories
[accessori]. The link table is products_accessories
[accessori_prodotti] and have the two pks of the other tables. However, in addition to that, I need to store two optional extra fields that describe the link: minimum_qty
[quantita_minima] and obligatory
[obbligatorio].
I digged into other threads on this forum and found out it's not possible to manage this situation out of the box, so I tried to achieve this with nested editing.
What I have now is that the main editor form allows to link accessories to a product, and the nested editor allows for every row to add the additional fields.
However it seems it's not working: the nested editor doesn't save any data back to the main editor form, and the preSubmit log of the nested editor looks suspicious, eg:
preSubmit edit {"data":{"[object HTMLTableRowElement]":{"accessori_prodotti":{"quantita_minima":"2","obbligatorio":"1"}}},"action":"edit"}
.
I was wondering if it's something feasible or if I'm on the wrong path.
This is the main editor:
var editor = new DataTable.Editor({
ajax: 'dt-php/table.ACCESSORI.php',
table: '#accessoriprodotti',
fields: [
{
label: 'Codice:',
name: 'prodotti.codice'
},
{
label: 'Alfanumerico:',
name: 'prodotti.alfanumerico'
},
{
label: '',
name: 'accessori_joined[].alfanumerico',
type: 'datatable',
multiple: true,
optionsPair: {
value: 'alfanumerico'
},
config: {
paging: false,
scrollY: 250,
scrollCollapse: false,
editor: editorAttributiAssociazioni,
buttons: [
{ extend: 'edit', editor: editorAttributiAssociazioni }
],
columns: [
{
title: 'Codice',
data: 'codice'
},
{
title: 'Alfanumerico',
name: 'alfanumerico',
data: 'alfanumerico'
},
{
title: 'Descrizione',
name: 'descrizione_sintetica',
data: 'descrizione_sintetica'
},
{
title: 'Q.min',
data: 'accessori_prodotti.quantita_minima',
name: 'accessori_prodotti.quantita_minima'
},
{
title: 'Obb.',
data: 'accessori_prodotti.obbligatorio',
name: 'accessori_prodotti.obbligatorio',
type: "checkbox",
options: [
{ label: '', value: 1 }
],
separator: '',
unselectedValue: 0,
defaultContent : 0
},
{
data: null,
defaultContent: '<i class="bi bi-pencil-square"></i>'
}
]
}
}
}
]
});
and this is the nested editor:
var editorAttributiAssociazioni = new DataTable.Editor({
idSrc: 'alfanumerico',
fields: [
{
label: 'Quantità minima',
name: 'accessori_prodotti.quantita_minima', def: 1, attr: { min: 0 }
},
{
label: 'Obbligatorio',
name: 'accessori_prodotti.obbligatorio',
type: 'checkbox',
options: [{ label: '', value: 1 }],
separator: ','
}
]
});
Do you have any suggestion on this problem? Thank you in advance
Answers
The child editor should contain two foreign keys - because it is a link table - and the additional fields. No data need to be saved "back to the main editor form".
It is just regular parent - child editing with the child table being a link table in addition. What you need in your child editor is e.g. a "select" field that allows you the selection of the "other" foreign key from the "other" parent table.
Take a look at this example please:
https://editor.datatables.net/examples/datatables/parentChild
Please also note the usage of "submit: false".
Too bad I don't have a use case with field type "datatable" for your case. I have many use cases of it from the time BEFORE field type "datatable" was introduced. I solved the problem by having a button on one of the parent tables that allowed opening a child data table with a child Editor which also allowed the foreign key selection from the "other" parent data table. If you are interested in that, I could post something.
Thank you, I've checked that example already but I believe it's not as close to my case as I'd hope.
This is the main editor form:
Columns
Codice
,Alfanumerico
andDescrizione
are coming from the mjoin options list. ColumnsQ.min
andObb.
are the extra columns present on the link table, but are not present as data on the options parameter coming from PHP editor (because they're not about the accessory to be linked, but about the already existing link.This is the child editor form:
but it's not working, and don't actually know if it can be done with a N:M type of relationship.
About your use case, if I got it right, on the child editor you have to select again what parent row you're editing? What I'd like to achieve is clicking on the pencil icon on the right of the parent editor row, and have the child editor to be directly setted on that record and, so, foreign key.
Right now, as a plan B, I created a brand new page based 1:1 with the link table on the database, to allow the edit of the extra fields. But with that, every update on the association between a product and accessories, resets all extra fields.
Not really. That selection is implicit. But you need to select the second parent table's foreign key.
What are the error message you are getting?
In your code I don't understand this:
It's either redundant or maybe even harmful. It's clear that your child table can have multiple records. That doesn't need to be specified.
I don't see this line:
If you don't have this line it means that accessori_joined[].alfanumerico is being submitted to the server. That usually causes a crash in parent child editing.
I had this in my code BEFORE Allan introduced "submit: false"
I will post a simple example from my own coding in the subsequent post.
I have a parent child Editor window with one parent editor (just the first two fields) and three child editors. I will limit this post to the first child.
So this is the parent Editor. 2 fields and then the field of type "datatable":
I don't need "optionsPair" or "multiple".
And this is part of the child Editor (many fields - not interesting).
The PHP for the child Editor is not interesting. It is just like any other Editor. Please note: Since we set "submit: false" there are absolutely no changes to the parent PHP Editor because nothing from the child Editor is submitted via the parent!
Since the parent ID is not part of the child Editor I need to send it to the server in the child Editor somehow. It is the ID of the selected parent record.
Here is the relevant part in the PHP of the child Editor:
And here is the JS for it (as stated above already). parentId and the other variable posted are taken from the selected parent record.
I'm kind of lost, since I can't figure out if it's something that can be done with additional fields that are directly present inside the link table, with a many-to-many relationship between two tables (products and accessories).
Since the example of the parent-child editing doesn't have the Server code section, I find it difficult to transpose that to my case.
This is currently the schema of this part of app:

Does this parent-child editing need the extra fields to be on another table that references the link table?
Your case is straightforward and should work just the same way as the example from my own coding I presented above. Please try to adapt it. If you need more of my server PHP code just let me know. The fact that you are calling id fields "SKU" makes it a little more difficult because you need to make sure Editor knows this.
No!
Looking at your code again I noticed that your nested Editor cannot work because you are not passing the parentID to the server as in my example above.
Thank you for the check!
Can I ask you the server code for the parent and the child editor of your case?
The server code of the parent Editor is huge because it is a very large data table with half a dozen JS Editors for it. So I can only give you a small excerpt from that. The total length of the server code for the parent Editor is 1,271 lines of code ... As I said, the parent Editor has absolutely no reference to the client Editor. So it is fairly unimportant anyway.
As you can see I don't need to specify the primary key of database table "ctr" because it is called "id".
But here is the code excerpt from the parent Editor:
And the code of the child Editor.
As you can see there is no options instance in the server code of the child table because my child table isn't a link table. You will need an options instance to select the options of the foreign key from the second parent table!
The following editor is for parent child editing (I don't use field type "datatable" on the client side but that doesn't matter for the server side code! I coded this before field type "datatable" was introduced by Allan.)
This code edits a link table between USER and DEPARTMENT for the selected user. The link table is called "govdept_has_user" it contains the link between the two parent tables plus the role the user has for the selected department. The only editable fields in this editor are "govdept_has_user.govdept_id" i.e. the foreign key from the second parent table and "govdept_has_user.role" i.e. the role the user has for that department
about your last example, does the parent editor server code use an Mjoin instance? Or does the link between the two records get created by the child editor with the two foreign key, that come from the parent editor via the ajax.data function?
I'm still trying to find out a way to set this up, but I'm not confident with the underlying working principle.
Would you mind sharing (the entire/a part) of the javascript of your last example?
Thank you very much for your time, I really appreciate.
What I'm worried about is that it's something that can't be done, since on this thread Allan clearly stated it was not possible
The child editor creates the link! The parent editor does nothing in that regard.
By the way, my parent editor contains an Mjoin. But that is read-only!! Why? because an Mjoin can only edit link tables that consist of 2 fields: both MUST be foreign keys from the respective parent table. So the following Mjoin in the parent Editor is completely irrelevant for parent child editing. It is only used for displaying the content of the child table in the parent table at the front end. That is very important to understand!
No worries: I've been doing this for 8 years now! With and without field type "datatable". But again: You can't do it with an Mjoin! And that is what Allan is saying in the thread you are linking to:
Amazing information @rf1234 - thank you for sharing this. If this forum had badges like SO, I'd be adding "parent / child editing master" to your account
. Looking forward to discussing this type of editing further with you.
Yes, that is still correct for an
Mjoin
with a link table. However, based on what I've read above, I think your situation is quite possible using the example @rf1234 linked to and not usingMjoin
. The key difference would be that instead of showing a list of all accessories, you show only the accessories that have been assigned.One question though: what is the table
accessori_joined
and how does it relate toaccessori_prodotti
? It is mentioned in your first post, but no where else.There are so many ways of doing parent / child editing that it is all quite confusing, but in this case, what I would be tempted to do initially is setup regular Editor instance for
accessori_prodotti
and apply a WHERE filter to specify a single product. Also useField::inst('product_sku')->setValue(3)
(where 3 is changed to be whatever the product primary key is - i.e. the same as your WHERE filter).Then you can add / edit / remove items from
accessori_prodotti
making a link to a single product, while setting the values for such as if it is obligatory, min quantity, etc. To select the accessory, you could usetags
,select
ordatatable
depending on what interface you want to present to the user.Once you've got it working for a single product, we just need to generalise it, and that's where the example @rf1234 linked to comes it - you could think of it as just a wrapper to select a different product.
One step at a time - create an Editor for
accessori_prodotti
with a single product selected! Don't use Mjoin - it isn't needed in this case.Allan
Almost
This picture suggests that the parent Editor is on "accessori" and not on "prodotti". So it is probably the other way round:
- Select an accessory
- then open the child Editor to select a "prodotto"
- and to edit the additional attributes.
In my example above I do the same:
- Select a user
- then open the child Editor to select a "govdept" (department)
- and to edit the role.
This is what my child Editor looks like (again: not field type "datatable" but a "regular" Editor that sits in a bootstrap model with its own little data table.)
This is the child data table in the bootstrap modal:

And the child Editor. Very simple you can select a department and a role. That populates table govdept_has_user above. Done.
Finally I have a column displaying the selected roles in the parent data table. That is populated with the "read-only" Mjoin as described above.
Thank you Allan!
Exactly @rf1234 , the parent editor is on "accessori" which is this page that used to show products and related accessories:

@allan I tried to go by steps and I created a table/editor for "accessori_prodotti" (product_accessories) link table that allows me to successfully set the two extra fields:

As a last resort this above might be fine, BUT extra fields get deleted whenever a product changes its accessories associations.
So the best way would be the parent editor (on "accessori") that lists all possible accessories for the selected product (e.g. "AAA"), and the link that is made by the child editor with the two extra fields.

But wouldn't this solutiong have the same issues of deleting extra data when the product-accessories association is edited?
Moreover, when I declare another editor + different ajax.url for the datatable field on the parent editor, I suspect that the options are expected to come from that url, but in my case are coming from the options array of "accessori". This is because the child editor only have the columns of the link table "prodotti_accessori" and doesn't have the list of accessories.
Gah! Thanks for spotting and correcting that.
Can you show me some code - what are you using to do this edit? Assuming you aren't using Mjoin, then that should be a simple table with a left join.
Allan