ItemPropertyChangeListener and nested entities not working

Hi all,

I have created a screen fragment that has an InstanceDataContainer, which in turn includes another instance container. Here’s an example:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<fragment xmlns="http://schemas.haulmont.com/cuba/screen/fragment.xsd">
	<data>
		<instance id="entityDc"
		          class="com.company.Entity"
		          view="Entity-view">
			<instance id="relatedEntityDc" property="relatedEntity" />
		</instance>

	</data>
	<layout>
		<form id="form" dataContainer="entityDc">
			<textField id="field1" property="field1" dataContainer="entityDc" />
			<textField id="field2" property="field2" dataContainer="entityDc" />
			<textField id="field3" property="field3" dataContainer="relatedEntityDc" />
		</form>
	</layout>
</fragment>

In the controller, I have something like this:

@Inject
private InstanceContainer<Entity> entityDc;

@Inject
private InstancePropertyContainer<RelatedEntity> relatedEntityDc;

@Subscribe
public void onInit(InitEvent event) {
	// Capture the changes of the Entity 
	entityDc.addItemPropertyChangeListener(propertyChangeEvent -> {
		entityDc.setItem(propertyChangeEvent.getItem());
	});

	// Capture the changes of the inner entity RelatedEntity
	relatedEntityDc.addItemPropertyChangeListener(propertyChangeEvent -> {
		relatedEntityDc.setItem(propertyChangeEvent.getItem());
	});
}

When I edit field1 or field2, the Table UI showing the list of entities (of type Entity) is automatically updated. However when I edit the field3, which belongs to the nested entity RelatedEntity, the Table UI doesn’t get updated. I checked with printing out messages, the event is generated on changes of field3 but the line relatedEntityDc.setItem(propertyChangeEvent.getItem()) seem not to have an effect. It seems that the “setItem” method doesn’t have an impact if nested entities get changed.

Any idea how can I get this working.

Thanks,
Samy

Hi Samy,

In fact, since CUBA v.7 you don’t need to create nested container to edit properties of nested entities. The following should work:

<textField id="field3" property="relatedEntity.field3" dataContainer="entityDc" />

If it doesn’t, please create a small test project demonstrating the problem (use gradlew zipProject to make an archive).

Hi Konstantin,

Here’s a sample project. If you try to modify the field1 or field2, the table data is updated. However updating field1 or field2 of the related entity doesn’t refresh the table.

entity-related.zip (81.5 KB)

Thanks for your help.

Best,
Samy

I have implemented a workaround that seems to work, but it is really ugly.

private Entity currentEntity;

@Subscribe(target = Target.DATA_CONTEXT)
public void onChange(DataContext.ChangeEvent event) {
           if(event.getEntity() instanceof RelatedEntity) {
                 dataContext.merge(event.getEntity())
                 if(currentEntity != null) {
                       String oldValue = currentEntity.getField1();
                       currentEntity.setField1("dummyData")
                       entityDc.setItem(entity)
                       currentEntity.setField1(oldValue)
                       entityDc.setItem(entity)
                 }
           }
    }

I think the issue in Cuba code is that changes of sub-entities are not firing the event due to reference equality for change check instead of object equality. As you can see, the workaround is not nice.

Hi Samy,

The project you have attached doesn’t work correctly because the related entity instance just doesn’t exist. You need to create it somehow, for example when you create the master entity:

public class MainEntityBrowse extends MasterDetailScreen<MainEntity> {

    @Inject
    private DataContext dataContext;

    @Subscribe
    public void onInitEntity(InitEntityEvent<MainEntity> event) {
        RelatedEntity relatedEntity = dataContext.create(RelatedEntity.class);
        event.getEntity().setField3(relatedEntity);
    }
}

Notice that the RelatedEntity instance is created using DataContext, which ensures the new instance will be saved when the screen commits.