0

以下是我的要求- 在此处输入图像描述

在这里,我有一个p:panelGrid可以添加和删除表格行的。网格包含一些p:inputText和各种其他 PrimeFaces 组件以及p:fileUpload每行中的一个组件。组件p:fileUpload设置了mode="advanced" auto="true"属性,上传成功后自动上传文件并隐藏自身。

整体p:panelGrid@ViewScoped,因此工作正常。我保留了p:fileUpload组件,@RequestScoped因为对于每个上传请求,它都必须上传文件,但是在添加新行之后,以前的状态不再保留。所以p:fileUpload在前面的行中也开始可见。那是我不想要的。我需要为它编写任何自定义范围吗?下面是视图-|

<h:form>
    <p:panel id="agentForm" header="#{msg.AGENTS_INFORMATION}"
        style="overflow:auto;  margin-bottom: 2px">
        <div align="center" style="margin-top: 20px; margin-bottom: 2px">
            <ui:repeat value="#{agent.scenarioList}" var="c">
                <p:panelGrid>
                    <p:row>
                        <p:column>
                            <p:inputText id="ipaddress" value="#{c.machineIpAddress}"
                                style="width:90%">
                                <p:watermark for="ipaddress" value="#{msg.MACHINE_IP_ADDRESS}" />
                            </p:inputText>
                        </p:column>
                        <p:column>
                            <p:inputText id="username" value="#{c.machineUsername}"
                                style="width:90%">
                                <p:watermark for="username" value="#{msg.MACHINE_USERNAME}" />
                            </p:inputText>
                        </p:column>
                        <p:column>
                            <p:password id="passwd" value="#{c.machinePassword}">
                                <p:watermark for="passwd" value="#{msg.MACHINE_PASSWORD}" />
                            </p:password>
                        </p:column>
                        <p:column id="fileUpload">
                            <p:fileUpload rendered="#{!fileUploadController.hidden}"
                                label="Upload Script" style="font-size: 100% !important;"
                                showButtons="false"
                                fileUploadListener="#{fileUploadController.upload}"
                                mode="advanced" auto="true" sizeLimit="100000"
                                allowTypes="/(\.|\/)(py|txt)$/"
                                update="fileUpload, outPanel, :message" />
                            <p:outputPanel id="outPanel">
                            <!-- Below outputLabel will be linked to uploaded file, so that User can see the file -->
                            <p:outputLabel style="cursor: pointer" value="View uploded Script"
                                    label="View Script" rendered="#{fileUploadController.hidden}" />
                            </p:outputPanel>
                        </p:column>
                        <p:column>
                            <p:inputText id="testname" value="#{c.testName}"
                                style="width:90%">
                                <p:watermark for="testname" value="#{msg.TEST_NAME}" />
                            </p:inputText>
                        </p:column>
                        <p:column>
                            <p:spinner id="threads" value="#{c.threads}" min="1" max="500"
                                size="8">
                                <p:tooltip for="threads" value="#{msg.TEST_NAME}"
                                    showEffect="slide" hideEffect="slide" />
                            </p:spinner>
                        </p:column>
                        <p:column>
                            <p:selectBooleanCheckbox id="chkSelected" value="#{c.selected}">
                                <p:tooltip for="chkSelected" value="#{msg.CHECKBOX}"
                                    showEffect="slide" hideEffect="slide" />
                            </p:selectBooleanCheckbox>
                        </p:column>
                    </p:row>
                </p:panelGrid>
            </ui:repeat>
            <p:toolbar style="margin-top: 10px;">
                <p:toolbarGroup align="right">
                    <p:commandButton value="#{msg.ADD_IT}"
                        update=":message, agentForm"
                        actionListener="#{agent.addComponent()}" />
                    <p:commandButton value="#{msg.DELETE_IT}"
                        update=":message, agentForm"
                        actionListener="#{agent.deleteComponent()}" />
                </p:toolbarGroup>
            </p:toolbar>
        </div>
    </p:panel>
</h:form>

我的托管 bean@ViewScoped看起来像这样-

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import org.ravij.performance.model.Scenario;
@ManagedBean(name = "agent")
@ViewScoped
public class AgentInfo implements Serializable {
    private static final long serialVersionUID = 1L;
    List<Scenario> scenarioList;
    @PostConstruct
    public void initBean() {
        this.scenarioList = new ArrayList<Scenario>();
        this.scenarioList.add(new Scenario());
    }
    public void addComponent() {
        if (this.scenarioList != null) {
            this.scenarioList.add(new Scenario());
        } else {
            this.initBean();
        }
    }
    public void deleteComponent() {
        List<Scenario> itemsToDelete = new ArrayList<Scenario>();
        if (this.scenarioList != null) {
            for (Scenario b : this.scenarioList) {
                if (b.isSelected()) {
                    itemsToDelete.add(b);
                }
            }
            this.scenarioList.removeAll(itemsToDelete);
        }
    }
    public List<Scenario> getScenarioList() {
        return scenarioList;
    }
    public void setScenarioList(List<Scenario> scenarioList) {
        this.scenarioList = scenarioList;
    }
}

Scenario 对象包含一行的所有信息。下面是代码-

package org.ravij.performance.model;
import java.io.Serializable;
public class Scenario implements Serializable {
    private String machineIpAddress;
    private String machineUsername;
    private String machinePassword;
    private String uploadedFilePath;
    private String testName;
    private int threads = 1;
    private boolean selected = false;

    //Below are the getters and setter w.r.t all the above variables
    //I am not putting it, to make the code short
}

托管 beanFileUploadController位于@RequestScoped

4

1 回答 1

1

您应该简单地将hidden属性与@ViewScopedbean 中的其他值保持一致。hidden您当前的代码具有与您的所有组件共享的单个属性,<p:fileUpload这可能不是您想要的。

该行为看起来不错,因为您只更新当前的fileUpload,但根据您的代码,所有其他<p:fileUpload组件都应该被隐藏。

您还应该将您的内容<h:form放入您<ui:repeat的文件中,以便您可以通过将索引(您可以从<ui:repeatusingvarStatus属性中获取)或任何其他标识符以匹配当前行隐藏输入。

#{fileUploadController.upload}获取隐藏参数的最简单方法是从此处获取响应:FacesContext如何从 <ui:repeat> 中的 jsf 页面获取参数到 BackingBean

更新

这比预期的要难一些,问题是<p:fileUpload它将以封闭的形式发送所有内容(没有尝试使用process属性),因此很难知道文件上传涉及哪一行。

另外,我不知道您不能放入<h:form您的<ui:repeat但删除按钮的行为是阻塞的,因为它希望以一种形式获得所有内容。

我使用对话框制作了一个工作 POC,将文件上传放在外面,方法如下:

琐碎的 Scenario.java :

public class Scenario implements Serializable {

    private String machineIpAddress;
    private String machineUsername;
    private String machinePassword;
    private String uploadedFilePath;
    private String testName;
    private int threads = 1;
    private boolean selected = false;
    private boolean hidden = false; // This is new

    // + Getters/Setters
}

AgentInfo.java 中的一些更改:

@ManagedBean(name = "agent")
@ViewScoped
public class AgentInfo implements Serializable {

    private List<Scenario> scenarioList;

    private Scenario currentScenario; // This is new

    // I removed the @PostConstruct which I rarely use

    public void addComponent() {
        if (this.scenarioList != null) {
            this.scenarioList.add(new Scenario());
        }
    }

    public void deleteComponent() {
        if (this.scenarioList == null) {
            return;
        }

        List<Scenario> itemsToDelete = new ArrayList<Scenario>();

        for (Scenario scenario : this.scenarioList) {
            if (scenario.isSelected()) {
                itemsToDelete.add(scenario);
            }
        }

        this.scenarioList.removeAll(itemsToDelete);
    }

    // This is new, it must be called before opening the upload dialog
    // in order to keep a pointer on the current scenario you are working on
    public void prepareUpload(Scenario scenario) {
        this.currentScenario = scenario;
    }

    // I put the upload method here
    public void upload(FileUploadEvent event) {
        // Do what you need to do here
        this.currentScenario.setHidden(true);
        RequestContext.getCurrentInstance().execute("uploadDialogWidget.hide()");
    }

    public List<Scenario> getScenarioList() {
        if (this.scenarioList == null) {
            this.scenarioList = new ArrayList<Scenario>();
            this.scenarioList.add(new Scenario());
        }

        return scenarioList;
    }

    public void setScenarioList(List<Scenario> scenarioList) {
        this.scenarioList = scenarioList;
    }

    public Scenario getCurrentScenario() {
        return currentScenario;
    }

    public void setCurrentScenario(Scenario currentScenario) {
        this.currentScenario = currentScenario;
    }
}

最大的变化是在视图中,我<h:commandButton在表单中放了一个打开对话框。我还添加了对话框,并redisplay为您的密码字段添加了属性(如果您想在提交表单后保留该值,这是必需的)。请注意,我删除了对message未提供 id 的组件的引用,不要忘记重新引入它。.xhtml :

<h:form id="agentForm">
    <p:panel header="#{msg.AGENTS_INFORMATION}"
        style="overflow:auto;  margin-bottom: 2px">
        <div align="center" style="margin-top: 20px; margin-bottom: 2px">
            <ui:repeat value="#{agent.scenarioList}" var="c">
                <p:panelGrid>
                    <p:row>
                        <p:column>
                            <p:inputText id="ipaddress" value="#{c.machineIpAddress}"
                                style="width:90%">
                                <p:watermark for="ipaddress" value="#{msg.MACHINE_IP_ADDRESS}" />
                            </p:inputText>
                        </p:column>
                        <p:column>
                            <p:inputText id="username" value="#{c.machineUsername}"
                                style="width:90%">
                                <p:watermark for="username" value="#{msg.MACHINE_USERNAME}" />
                            </p:inputText>
                        </p:column>
                        <p:column>
                            <p:password id="passwd" value="#{c.machinePassword}" redisplay="true">
                                <p:watermark for="passwd" value="#{msg.MACHINE_PASSWORD}" />
                            </p:password>
                        </p:column>
                        <p:column id="fileUpload">
                            <p:commandButton icon="ui-icon-arrowthick-1-n" value="Upload"
                                             actionListener="#{agent.prepareUpload(c)}"
                                             update=":uploadDialog"
                                             oncomplete="uploadDialogWidget.show()"
                                             rendered="#{!c.hidden}" />
                            <p:outputPanel id="outPanel">
                            <!-- Below outputLabel will be linked to uploaded file, so that User can see the file -->
                            <p:outputLabel style="cursor: pointer" value="View uploded Script"
                                    rendered="#{c.hidden}" />
                            </p:outputPanel>
                        </p:column>
                        <p:column>
                            <p:inputText id="testname" value="#{c.testName}"
                                style="width:90%">
                                <p:watermark for="testname" value="#{msg.TEST_NAME}" />
                            </p:inputText>
                        </p:column>
                        <p:column>
                            <p:spinner id="threads" value="#{c.threads}" min="1" max="500"
                                size="8">
                                <p:tooltip for="threads" value="#{msg.TEST_NAME}"
                                    showEffect="slide" hideEffect="slide" />
                            </p:spinner>
                        </p:column>
                        <p:column>
                            <p:selectBooleanCheckbox id="chkSelected" value="#{c.selected}">
                                <p:tooltip for="chkSelected" value="#{msg.CHECKBOX}"
                                    showEffect="slide" hideEffect="slide" />
                            </p:selectBooleanCheckbox>
                        </p:column>
                    </p:row>
                </p:panelGrid>
            </ui:repeat>
            <p:toolbar style="margin-top: 10px;">
                <p:toolbarGroup align="right">
                    <p:commandButton value="#{msg.ADD_IT}" update="agentForm"
                                     actionListener="#{agent.addComponent()}" />
                    <p:commandButton value="#{msg.DELETE_IT}" update="agentForm"
                        actionListener="#{agent.deleteComponent()}" />
                </p:toolbarGroup>
            </p:toolbar>
        </div>
    </p:panel>
</h:form>
<p:dialog id="uploadDialog" widgetVar="uploadDialogWidget" header="File upload">
    <h:form rendered="#{!empty agent.currentScenario}">
        <p:fileUpload
            label="Upload Script" style="font-size: 100% !important;"
            showButtons="false"
            fileUploadListener="#{agent.upload}"
            mode="advanced" auto="true" sizeLimit="100000"
            allowTypes="/(\.|\/)(py|txt)$/"
            update=":agentForm">
        </p:fileUpload>
        <p:commandButton value="Cancel" onclick="uploadDialogWidget.hide();" onstart="return false;" />
    </h:form>
</p:dialog>

您应该考虑从<p:panelGrid一个<p:dataTable具有内置机制来处理行选择的移动。

于 2013-04-04T23:47:22.177 回答