1

在我当前的项目中,我希望能够在搜索参考对象时创建新对象。这发生在应用程序的几个地方。

例如,假设我们有一个城市实体和一个国家实体。City 实体强制引用 Country 实体。

在我的用例中,我想创建一个新城市。当我这样做时,我将不得不为新城市分配一个国家。当我单击查找图标时,我会看到所有现有国家/地区的选择对话框。但是,如果我没有想要的国家/地区,我必须中止操作,返回国家/地区列表并创建一个我想分配给我的新城市的新国家/地区。

  1. 是否有可能从所有国家的选择对话中创建新的国家?
  2. 如果可能,该国家/地区是否在创建后立即添加到列表中?
  3. 是否可以为国家列表定义一个范围?例如,如果用户在欧洲,则仅显示欧洲的国家/地区。

我可以想象,这对框架有很多要求。但我只是试一试,也许还提供了一个新的功能想法,如果有的话会很高兴。

4

1 回答 1

3

LOV 对话框的自定义:

您可以通过创建您自己的安装在参考字段旁边的 LOV 操作类轻松自定义 LOV 对话框。

  • 在对话框中添加新操作(创建操作):
public class LovActionWithCreate<E, F, G> extends LovAction<E, F, G> {

  private IDisplayableAction createAction;

  @Override
  protected void feedContextWithDialog(IReferencePropertyDescriptor<IComponent> erqDescriptor,
                                       IQueryComponent queryComponent, IView<E> lovView, IActionHandler actionHandler,
                                       Map<String, Object> context) {
    super.feedContextWithDialog(erqDescriptor, queryComponent, lovView, actionHandler, context);
    List<IDisplayableAction> defaultLovDialogActions = (List<IDisplayableAction>) context.get(
        ModalDialogAction.DIALOG_ACTIONS);
    defaultLovDialogActions.add(1, getCreateAction());
  }

  /**
   * Gets create action.
   *
   * @return the create action
   */
  protected IDisplayableAction getCreateAction() {
    return createAction;
  }

  /**
   * Sets create action.
   *
   * @param createAction
   *     the create action
   */
  public void setCreateAction(IDisplayableAction createAction) {
    this.createAction = createAction;
  }
}

关键是要覆盖该feedContextWithDialog方法,以便将新操作安装到对话框中。

下一步是安装新的 LOV 操作。您可以为整个应用程序或每个参考视图全局执行此操作:

  • 全局替换 LOV 操作只是在'lovAction'您的应用程序中声明一个名为的操作frontend.groovy,即:
action('lovAction', parent: 'lovActionBase', class:'test.LovActionWithCreate',
    custom: [createAction_ref:'theCreateAction']
)
  • referencePropertyView可以通过使用(in aform或 in a table) 及其 'lovAction' 属性来替换表单中某个参考字段上的 LOV 操作,例如:
action('lovActionWithCreate', parent: 'lovActionBase', class:'test.LovActionWithCreate',
    custom: [createAction_ref:'theCreateAction']
)

form('ACertainForm'){
  fields {
    ...
    referencePropertyView name:'country', lovAction:'lovActionWithCreate'
    ...
  }
}

在 LOV 对话框中创建实体:

在下一步中,我们将创建将负责打开额外对话框的操作,以创建新实体并将其持久化,如果成功,则将其添加到 LOV 结果视图。这有点复杂,但不是那么多。

  • 首先,我们必须打开一个新对话框。

为此,我们将继承内置的EditComponentAction. 此操作的目标是在模态对话框中编辑模型。这里唯一的困难是我们的模型只在运行时才知道。没问题,因为我们将使用 Jspresso 的动态特性。

public class CreateEntityFromLOVAction<E, F, G> extends EditComponentAction<E,F,G> {

  @Override
  protected Object getComponentToEdit(Map<String, Object> context) {
    IEntityFactory entityFactory = getBackendController(context).getEntityFactory();
    IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
    Class<IEntity> entityToCreateContract = lovQueryComponent.getQueryContract();

    IEntity entityInstance = entityFactory.createEntityInstance(entityToCreateContract);
    setActionParameter(Arrays.asList(entityInstance), context);
    return entityInstance;
  }

  @Override
  protected IViewDescriptor getViewDescriptor(Map<String, Object> context) {
    IEntityFactory entityFactory = getBackendController(context).getEntityFactory();
    IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
    Class<IEntity> entityToCreateContract = lovQueryComponent.getQueryContract();
    IComponentDescriptor<?> entityToCreateDescriptor = entityFactory.getComponentDescriptor(entityToCreateContract);

    BasicComponentViewDescriptor formViewDescriptor = new BasicComponentViewDescriptor();
    formViewDescriptor.setModelDescriptor(entityToCreateDescriptor);
    return formViewDescriptor;
  }
}

如果您查看上面的代码,我们的新操作会处理以下内容:

  1. 从上下文中获取要创建的实体类型。为此,我们只是探索作为 LOV 对话模型的查询组件。
  2. 创建实体实例并将其设置为上下文中的操作参数,以便链继续对其进行处理(保存、关闭对话框)。
  3. 创建要在创建对话框中显示的表单。

第 1 点和第 2getComponentToEdit点由方法处理,第 3 点由getViewDescriptor方法处理。

  • 接下来,当用户单击 时Ok,我们必须保存实体,将其添加到 LOV 结果列表并关闭创建对话框。

为此,我们将创建一个新动作并将其链接到saveAction内置closeDialogAction动作。

public class CreateEntityFromLOVPersistAction<E, F, G> extends FrontendAction<E,F,G> {

  @Override
  public boolean execute(IActionHandler actionHandler, Map<String, Object> context) {
    if (super.execute(actionHandler, context)) {
      IQueryComponent lovQueryComponent = (IQueryComponent) context.get(IQueryComponent.QUERY_COMPONENT);
      List<IEntity> createdEntityInstance = getActionParameter(context);

      lovQueryComponent.setQueriedComponents(createdEntityInstance);
      return true;
    }
    return false;
  }
}
  • SJS 中的最终布线frontend.groovy
action('createEntityFromLovOkAction', parent: 'okDialogFrontAction',
        class:'test.CreateEntityFromLOVPersistAction',
       wrapped: 'saveBackAction', next: 'closeDialogAction')

action('createEntityFromLovAction', parent: 'editComponentAction',
        class: 'test.CreateEntityFromLOVAction',
       name:'add.name', custom: [
           okAction_ref: 'createEntityFromLovOkAction'
       ]
)

action('lovAction', parent: 'lovActionBase',
        class:'test.LovActionWithCreate',
    custom: [createAction_ref:'createEntityFromLovAction']
)

不到 100 行代码的长答案,但现在您拥有一个完全通用的 LOV 操作,用户可以在其中创建任何缺失的主数据,而无需离开当前屏幕。

根据用户上下文在 LOV 过滤器中预设一些数据:

为此,我们通常使用允许在 LOV 中查询引用属性时设置一些限制(静态或动态)的初始化映射。例如,让我们考虑以下用例:

  • 您有 2 个实体ContractTariff,它们通过 1-N 关系链接在一起,即 aContract链接到 1 Tariff
  • Contract并且Tariff两者都有一个country属性,并且当且仅当它们属于同一个国家时,Tariff才能将 a 分配给 a 。Contract
  • Tarrif有一个status属性,并且只能在 a 中使用,Contract如果它statusACTIVE

您可以通过以下方式在引用属性上设置初始化映射来简单地在 LOV 中强制执行这些规则:

Entity('Contract', ...) {
  ...
  reference 'tariff', ref: 'Tariff',
       initializationMapping: [
            'country': 'country',
            'status': 'ACTIVE'
       ]
  ...
}

想一想,这种行为很可能会在框架中找到,所以请随时在Jspresso GitHub中打开增强请求。

于 2015-08-28T13:31:02.057 回答