Skip to content

Commit

Permalink
Fragments jmix-framework#841 (set declarative parameters after autowi…
Browse files Browse the repository at this point in the history
…ring)
  • Loading branch information
glebfox committed Jun 13, 2024
1 parent 8166e74 commit f250c4d
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,25 +102,26 @@ public void init(ComponentLoader.Context hostContext, Fragment<?> fragment) {
FragmentActions actions = applicationContext.getBean(FragmentActions.class, fragment);
FragmentUtils.setFragmentActions(fragment, actions);

FragmentLoaderContext context;
String descriptorPath = FragmentUtils.resolveDescriptorPath(fragment.getClass());
if (descriptorPath != null) {
FragmentLoaderContext context = new FragmentLoaderContext();
context = new FragmentLoaderContext();
context.setFragment(fragment);
context.setFullOriginId(getFullOriginId(hostContext, fragment));
context.setMessageGroup(FragmentUtils.getMessageGroup(descriptorPath));
context.setActionsHolder(actions);
context.setParentContext(hostContext);

processFragmentDescriptor(context, descriptorPath);

context.executeInitTasks();
} else {
context = null;
}

ComponentLoader.Context hostLoaderContext = findHostLoaderContext(hostContext);
if (hostLoaderContext instanceof ComponentLoader.ComponentContext componentContext) {
componentContext.addAutowireTask(context -> autowireFragment(fragment));
componentContext.addAutowireTask(__ -> postInit(fragment, context));
} else {
autowireFragment(fragment);
postInit(fragment, context);
}
}

Expand All @@ -134,11 +135,24 @@ protected String getFullOriginId(ComponentLoader.Context hostContext, Fragment<?
fragmentId.orElse(fragment.getClass().getSimpleName());
}

protected void postInit(Fragment<?> fragment, @Nullable FragmentLoaderContext context) {
autowireFragment(fragment);

// Init tasks should be executed after fragment is autowired,
// but before ReadyEvent. In particular, this is needed to make
// sure that setting properties from XML is processed after
// UI components are injected which so properties are handled
// the same for declarative creation of fragment and programmatic
if (context != null) {
context.executeInitTasks();
}

ComponentUtil.fireEvent(fragment, new Fragment.ReadyEvent(fragment));
}

protected void autowireFragment(Fragment<?> fragment) {
FragmentAutowireContext fragmentAutowireContext = new FragmentAutowireContext(fragment);
autowireManager.autowire(fragmentAutowireContext);

ComponentUtil.fireEvent(fragment, new Fragment.ReadyEvent(fragment));
}

@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import io.jmix.flowui.Fragments;
import io.jmix.flowui.exception.GuiDevelopmentException;
import io.jmix.flowui.fragment.Fragment;
import io.jmix.flowui.xml.layout.inittask.AbstractInitTask;
import io.jmix.flowui.xml.layout.loader.AbstractComponentLoader;
import io.jmix.flowui.xml.layout.loader.PropertiesLoaderSupport;

Expand All @@ -44,9 +45,17 @@ public void loadComponent() {
applicationContext.getBean(Fragments.class).init(context, resultComponent);

if (element.element("properties") != null) {
PropertiesLoaderSupport propertiesLoader =
applicationContext.getBean(PropertiesLoaderSupport.class, context);
propertiesLoader.loadProperties(resultComponent, element);
// setting properties from XML should be processed after UI components
// are injected which so properties are handled the same for declarative
// creation of fragment and programmatic
getContext().addInitTask(new AbstractInitTask() {
@Override
public void execute(Context context) {
PropertiesLoaderSupport propertiesLoader =
applicationContext.getBean(PropertiesLoaderSupport.class, context);
propertiesLoader.loadProperties(resultComponent, element);
}
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.vaadin.flow.component.icon.VaadinIcon
import com.vaadin.flow.data.provider.Query
import component.fragment.component.*
import component.fragment.view.TestFragmentHostView
import component.fragment.view.TestParametersFragmentHostView
import component.standarddetailview.view.BlankTestView
import io.jmix.core.DataManager
import io.jmix.flowui.Fragments
Expand Down Expand Up @@ -387,6 +388,17 @@ class FragmentTest extends FlowuiTestSpecification {
fragment2.message == "Replacement"
}

def "Parameters are set after UI components are injected"() {
def parent = navigateToView(BlankTestView)

when:
viewNavigators.view(parent, TestParametersFragmentHostView)
.navigate()

then:
noExceptionThrown()
}

@Nullable
private static String getIconAttribute(Component icon) {
return icon != null ? icon.element.getAttribute("icon") : null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package component.fragment.component;

import com.vaadin.flow.component.formlayout.FormLayout;
import io.jmix.flowui.component.combobox.EntityComboBox;
import io.jmix.flowui.component.textfield.TypedTextField;
import io.jmix.flowui.fragment.Fragment;
import io.jmix.flowui.fragment.FragmentDescriptor;
import io.jmix.flowui.model.CollectionContainer;
import io.jmix.flowui.view.ViewComponent;
import test_support.entity.sales.Product;

@FragmentDescriptor("test-parameters-fragment.xml")
public class TestParametersFragment extends Fragment<FormLayout> {

@ViewComponent
private EntityComboBox<Product> entityField;
@ViewComponent
private TypedTextField<String> textField;

public void setContainer(CollectionContainer<Product> container) {
entityField.setItems(container);
}

public void setPlaceholder(String placeholder) {
textField.setPlaceholder(placeholder);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public class TestFragmentHostView extends StandardDetailView<Address> {
public TestHostFragment hostFragment;

@Autowired
public Fragments fragments;
private Fragments fragments;

public TestAddressFragmentProvided addressFragment;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2024 Haulmont.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package component.fragment.view;

import com.vaadin.flow.router.Route;
import component.fragment.component.TestAddressFragmentProvided;
import component.fragment.component.TestParametersFragment;
import io.jmix.flowui.Fragments;
import io.jmix.flowui.model.CollectionContainer;
import io.jmix.flowui.view.*;
import org.springframework.beans.factory.annotation.Autowired;
import test_support.entity.sales.Product;

@Route(value = "TestParametersFragmentHostView")
@ViewController
@ViewDescriptor("test-parameters-fragment-host-view.xml")
@EditedEntityContainer("addressDc")
public class TestParametersFragmentHostView extends StandardView {

@ViewComponent
private CollectionContainer<Product> productsDc;

@Autowired
private Fragments fragments;

@Subscribe
public void onInit(InitEvent event) {
TestParametersFragment fragment = fragments.create(this, TestParametersFragment.class);
fragment.setContainer(productsDc);
fragment.setPlaceholder("Placeholder");

getContent().add(fragment);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!--
~ Copyright 2024 Haulmont.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<fragment xmlns="https://jmix.io/schema/flowui/fragment">
<content>
<formLayout>
<entityComboBox id="entityField" metaClass="test_Product"/>
<textField id="textField"/>
</formLayout>
</content>
</fragment>
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
~ Copyright 2024 Haulmont.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ https://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->

<view xmlns="https://jmix.io/schema/flowui/view">
<data>
<collection id="productsDc"
class="test_support.entity.sales.Product">
<fetchPlan extends="_base"/>
<loader id="productsDl" readOnly="true">
<query>
<![CDATA[select e from test_Product e]]>
</query>
</loader>
</collection>
</data>
<facets>
<dataLoadCoordinator auto="true"/>
</facets>
<layout>
<fragment class="component.fragment.component.TestParametersFragment">
<properties>
<property name="container" value="productsDc" type="CONTAINER_REF"/>
<property name="placeholder" value="Placeholder"/>
</properties>
</fragment>
</layout>
</view>

0 comments on commit f250c4d

Please sign in to comment.