【问题标题】:How to manually instantiate a viewscoped bean multiple times如何多次手动实例化一个viewscoped bean
【发布时间】:2017-09-17 14:17:30
【问题描述】:

我正在使用 JSF 构建一个单页应用程序,看起来像这样:

左侧的菜单是动态生成的,单击其中一个子菜单会创建一个选项卡,我在其中显示来自 <ui:include> 的内容。

菜单和选项卡代码:

<p:layoutUnit position="west" resizable="false" size="210">
    <h:form id="menu_form">
        <p:panelMenu style="width:200px" model="#{homeView.menu}" />
    </h:form>
</p:layoutUnit>

<p:layoutUnit id="center-layout" position="center">

    <p:tabView id="tabss" style="font-size: 15px"
        activeIndex="#{homeView.index}" scrollable="true">
        <p:ajax event="tabClose" listener="#{homeView.onTabClose}"
            update="tabss" />
        <p:ajax event="tabChange" listener="#{homeView.onTabChange}"
            update="tabss" />

        <c:forEach items="#{homeView.openTabs}" var="otab">
            <p:tab title="#{otab.title}" closable="true"
                style="font-size: 15px" rendered="#{otab.open}">
                <p:scrollPanel mode="native" styleClass="scrollPanels">
                    <ui:include src="#{otab.content}" />
                </p:scrollPanel>
            </p:tab>
        </c:forEach>
    </p:tabView>
</p:layoutUnit>

主页的支持 bean:

@ManagedBean
@ViewScoped
public class HomeView {

    private List<Tab> tabs;
    private List<Tab> openTabs;
    private int index;
    private TabService tabService;
    private MenuService menuService;
    private MenuModel menu;
    @ManagedProperty("#{loginView}")
    private LoginView loginView;

    @PostConstruct
    public void init() {
        tabService = new TabService();
        menuService = new MenuService();
        tabs = menuService.loadTabs(loginView.getUtilisateur().getProfile());
        openTabs = new ArrayList<Tab>();
        menu = menuService.loadMenu(loginView.getUtilisateur().getProfile());
    }

    public void addTab(String title) {
        if (tabService.check(openTabs, title)) {
            openTabs = tabService.addTab(tabs, openTabs, title);
        }
        if (tabService.getIndex(openTabs, title) != -1) {
            index = tabService.getIndex(openTabs, title);
        }
    }

    public void onTabClose(TabCloseEvent event) {
        String title = event.getTab().getTitle();
        String ti = openTabs.get(index).getTitle();
        openTabs = tabService.closeTab(openTabs, title);
        if (ti.equals(title)) {
            index = tabService.setIndex(index);
        } else {
            index = tabService.setIndex(openTabs, ti);
        }
    }

    public void onTabChange(TabChangeEvent event) {
        index = tabService.getIndex(openTabs, event.getTab().getTitle());
    }
    // Getters and setters

我应该注意,单击子菜单会调用addTab(Title) 方法来打开选项卡
每个包含的页面(显示在选项卡中的页面)都使用自己的 viewscoped bean,该 bean 在关闭选项卡后被销毁(参见上面的代码)。

问题:

在上面的屏幕截图中,我显示了一个选项卡,其中我在 &lt;p:dataTable&gt; 中显示搜索结果,我想要的行为是:
每当从数据表中选择一个元素时,我都想打开一个选项卡,在其中显示有关该元素的更多信息。对我来说重要的是能够同时打开多个选项卡(显示有关元素的更多信息)。
我想到的是创建一个 xhtml 来完成显示部分,以及一个 viewscoped bean 来支持所述页面。那么有没有办法手动实例化所述bean(每次用户单击按钮)然后用相应的数据填充它,这样我就可以多次重复使用同一个页面?
谢谢

【问题讨论】:

  • 为什么你需要元素信息页面作为一个信息显示页面进行viewscoped?除非您需要 viewscope ,否则您可以将其设置为 requestscoped ?
  • @OTM 从技术上讲,它不只是显示信息,我想在该页面中做的是:使用所选项目执行一些查询以获取要显示的数据(这将进入它的 init()方法),它会有一些命令按钮来执行更多的查询。使其 requestScoped 将允许它被多次实例化?
  • 是的,对于 requestscoped bean,它将被实例化多次,每个信息页面请求具体一个实例化。即使您在信息页面中有命令按钮,只要您在请求范围内维护数据,进一步提交也应该与 requestscoped 一起使用。
  • 我已经尝试过了,但只是更改选项卡算作请求并触发 bean 的销毁。因为在我的情况下,我想让 bean 保持活力,直到我关闭选项卡(正如我在问题中提到的那样)
  • 好的。如果您想多次使用同一个视图,我认为您不能拥有同一个 bean 的多个 viewscoped 实例。作为一种解决方法,您可以为多个信息页面请求使用相同的 viewscoped bean。当您打开信息页面时,您可以传递标识符。例如,1,2 分别用于信息页面一和二,并通过标识符将任何关联数据存储在集合中,并相应地在页面中进行变量绑定。

标签: java jsf primefaces


【解决方案1】:

作为一种解决方法,您可以为多个信息页面请求使用相同的 viewscoped bean。当您打开信息页面时,您可以将标识符作为参数传递。例如,1,2 分别用于信息页面一和二,并通过标识符将任何关联数据存储在集合中,并相应地在页面中进行变量绑定。

【讨论】:

    【解决方案2】:

    如果我很好理解您想要做什么,一种可能性是使用视图范围 bean 以编程方式评估表达式:

    FacesContext context = FacesContext.getCurrentInstance();
    ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();
    ELContext elContext = context.getELContext();
    ValueExpression vex = expressionFactory.createValueExpression(elContext, "#{viewBeanName}", ViewBeanClass.class);
    ViewBeanClass viewBean = (ViewBeanClass) vex.getValue(elContext);
    

    如果bean不存在则实例化,如果存在则返回。

    【讨论】:

    • 我猜你不是很明白。我想多次实例化同一个bean(每次用户从dataTable中选择一个项目)。
    • 好的,在将参数传递给 include 之前我已经这样做了: 在包含的 html 中你使用#{bean} 变量。我希望这会有所帮助
    • 我遇到的问题不是如何将参数传递给包含,而是我想多次打开同一个页面但每次使用不同的参数
    • 但是使用参数你可以将任何你想要的东西传递给同一个xhtml,只需在参数中使用一个数组或其他东西来迭代:
    • 感谢您的反馈我已经使用@OTM 建议解决了它(检查原始问题上的 cmets)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-21
    • 2016-06-08
    • 1970-01-01
    • 2013-02-01
    • 2015-03-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多