daryn
(Daryn L)
December 9, 2020, 4:34am
#1
Am wondering if it is possible to call the create function of a master detail screen?
I am trying to basically duplicate an entity. Something like follows:
@Named("table.create")
protected CreateAction<Plan> tableCreate;
@Subscribe("duplicatePlanButton")
protected void onDuplicatePlanButtonClick(Button.ClickEvent event) {
tableCreate.setNewEntitySupplier(() -> {
Plan plan = metadata.create(Plan.class);
plan.setName("some name");
return plan;
});
tableCreate.execute();
}
Of course, I am getting the “No such screen error” as there is no edit screen.
Is there any way to do this in a master detail type screen?
krivopustov
(Konstantin Krivopustov)
December 9, 2020, 7:21am
#3
Hi,
CreateAction
in master-detail screen is assigned a special handler, see MasterDetailScreen#initBrowseCreateAction
. That’s why it works but your call to execute()
doesn’t. But you can call its actionPerform()
method, so the correct modified handler will be invoked.
The following solution works for me:
@UiController("untitled6_Product.browse")
@UiDescriptor("product-browse.xml")
@LookupComponent("table")
@LoadDataBeforeShow
public class ProductBrowse extends MasterDetailScreen<Product> {
@Named("table.create")
private CreateAction<Product> tableCreate;
@Inject
private GroupTable<Product> table;
private Product prototype;
@Subscribe("duplicateBtn")
public void onDuplicateBtnClick(Button.ClickEvent event) {
prototype = table.getSingleSelected();
try {
tableCreate.actionPerform(event.getButton());
} finally {
prototype = null;
}
}
@Subscribe
public void onInitEntity(InitEntityEvent<Product> event) {
if (prototype != null) {
event.getEntity().setName(prototype.getName());
event.getEntity().setPrice(prototype.getPrice());
}
}
}
On “Duplicate” click, I save the currently selected in the table entity as a prototype, and then call action’s actionPerform()
.
The prototype is used it in the standard InitEntityEvent
handler to initialize the new entity instance.
daryn
(Daryn L)
December 9, 2020, 8:52am
#5
Thanks Konstantin, works great. I was scratching my head on that one!
daryn
(Daryn L)
December 9, 2020, 8:55am
#6
You wouldn’t happen to know how to also init one-to-many entities through this process? Specifically to avoid the new-entity commit context error?
e.g. say we were trying to duplicate an invoice with all the invoice lines with this type of structure
<instance id="invoiceDc"
class="com.company.Invoice" view="plan-view">
<loader id="invoiceDl"/>
<collection id="invoiceLinesDc" property="lines">
</collection>
</instance>
Or do I have to create a before commit listener?
krivopustov
(Konstantin Krivopustov)
December 9, 2020, 9:29am
#7
In the same InitEntityEvent
handler, something like this:
Invoice invoice = event.getEntity();
invoice.setLines(new ArrayList());
invoice.getLines().add(someLine1);
invoice.getLines().add(someLine2);
If you copy lines from another instance, don’t forget to change the reference to invoice in them.
daryn
(Daryn L)
December 9, 2020, 9:51am
#8
Ah yes - that is what I was doing.
But upon save was getting the “On trying to persist a new entity was found that was not marked cascade persist” error. It also said I could add the new entities to the DataContext which I am not sure how to do - or was wondering if it could be done in the screen class itself…
I was trying to figure out how to get around it without having to create a ‘before insert’ listener. But I have just created one now.
Cheers
krivopustov
(Konstantin Krivopustov)
December 9, 2020, 3:04pm
#9
Yes, try to create your Line
entities using DataContext.create()
method. See the docs: DataContext .
daryn
(Daryn L)
December 9, 2020, 10:35pm
#10
Awesome, thanks! Have always wondered how to do that…
On another note… I feel like the DataContext doc could do with a bit of an overhaul/update. Doesn’t describe the create method either.