如何在JSF中禁用页面/表单

6
对于我的应用程序,我希望有具有不同权限的用户。一种权限允许用户查看数据库中的数据,而另一种权限则允许他们编辑数据。在登录时,我将检查他们的权限以确定他们是否可以编辑数据。如果用户具有只读权限,我正在寻找一种禁用整个页面的方法。是否有一种简单的方法可以禁用<h:form>标记内的所有内容?我需要能够禁用多个页面,希望通过只查看后端bean中的一个布尔值就可以完成。任何帮助都将不胜感激。
-编辑- 是否有容器或类似于此的东西可以包装我输入的内容以进行禁用?这样,我只需要引用一个地方即可禁用,如果其他逻辑中需要设置自己的禁用属性,则可以留下每个字段?
6个回答

6

您可以将所有按钮、链接、输入字段(允许编辑的一切)指向后端Bean上相同的值,以此来禁用它们。

<h:inputText disabled="#{!bean.permissionToWrite}">

我不知道有什么方法可以禁用表单中的所有内容,但您可能不想这样做,因为您可能希望用户提交搜索查询(即搜索框)在表单内。
更新:回答Alex Larzelere的评论。
在我看来,在这种情况下最好使用“disabled”而不是“rendered”,因为您可能希望在“inputText”框中向用户显示字段的值,但不让他修改它。如果您不渲染它,他就看不到它。您也可以使用“outputText”来显示它,但那样您就必须维护两个元素而不是一个。
更新:回答问题中的编辑: 您可以将组件包装在“h:panelGroup”中,然后根据您的逻辑进行渲染或不渲染,但是您无法禁用“h:panelGroup”中包含的输入字段,您必须逐个禁用它们。

那可能是一个选项,但那将是很多工作。我希望有更优雅的解决方案,比如(我知道不可能)<h:form disable="#{bean.permission}" /> - SomeFatMan
@pakore:你的方法是正确的。但是如果我想一起禁用一组组件怎么办?如果我为每个组件使用disabled属性,那么它将为每个组件生成单独的HTTP请求,从后端获取相同的值!!! - Kishor Prakash
2
@Kishor,你可以使用变量。甚至不用大写字母,你也可以改进我的回答。 - pakore
这个答案已经不再是最好的了。最后一次更新是无效的(从一开始就不合法)。其他答案提供的解决方案中,我的是最少工作量的(使用http://showcase.omnifaces.org/taghandlers/massAttribute)。 - Kukeltje
我在7年前回答了这个问题...我猜框架从那时起已经改变了 :) - pakore
显示剩余2条评论

5

这个简单的自定义组件可以用来包裹其他组件,如果使用属性 disabled="true" 或评估为 true 的 EL 表达式,则会禁用它们。它的预期工作方式是,如果包装的组件已经被禁用,那么如果使用 disabledPanel(或 ajax 重新呈现)并将其设置为 disabled="true",则它不会被启用。该组件仅尝试禁用 UIInput 和 UICommand 组件,我认为这样是可以的,但也可以更改。

xmlns:fnc="http://myco.co.uk/fnc"
...
<fnc:disablePanel disabled="#{bean.isItDisabled}">
   <h:inputText/>
   ...
</fnc:disablePanel>
...

UIDisablePanel.java

package uk.co.myco.component;

import java.io.IOException;
import javax.faces.component.*;
import javax.faces.context.FacesContext;

/*
 * @author Brendan Healey (Oversteer)
 */

@FacesComponent("uk.co.myco.component.UIDisablePanel")
public class UIDisablePanel extends UIComponentBase {

    private enum PropertyKeys {
        disabled;
    }

    public UIDisablePanel() {
        setRendererType(null);
    }

    @Override
    public void encodeBegin(FacesContext context) throws IOException {

        boolean toDisable = isDisabled();
        processDisablePanel(this, toDisable);
        //super.encodeBegin(context);
    }

    public void processDisablePanel(UIComponent root, boolean toDisable) {

        /*
         * The key point here is that a child component of <x:disablePanel> may
         * already be disabled, in which case we don't want to enable it if the
         * <x:disablePanel disabled= attribute is set to true.
         */

        for (UIComponent c : root.getChildren()) {
            if (c instanceof UIInput || c instanceof UICommand) {
                if(toDisable) { // <x:disablePanel disabled="true">
                    Boolean curState = (Boolean) c.getAttributes().get("disabled");
                    if(curState == null || curState == false) {
                        c.getAttributes().put("UIPanelDisableFlag", true);
                        c.getAttributes().put("disabled", true);
                    }
                }
                else { // <x:disablePanel disabled="false">
                    if(c.getAttributes().get("UIPanelDisableFlag") != null) {
                        c.getAttributes().remove("UIPanelDisableFlag");
                        c.getAttributes().put("disabled", false);
                    }
                }
            }

            if (c.getChildCount() > 0) {
                processDisablePanel(c, toDisable);
            }
        }

    }

    @Override
    public String getFamily() {
        // Got to override it but it doesn't get called.
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public boolean isDisabled() {
        return (boolean) getStateHelper().eval(PropertyKeys.disabled, false);
    }

    public void setDisabled(boolean disabled) {
        getStateHelper().put(PropertyKeys.disabled, disabled);
    }
}

disablepanel.taglib.xml

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib version="2.0"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd">
    <namespace>http://myco.co.uk/fnc</namespace>
    <tag>
        <tag-name>disablePanel</tag-name>
        <component>
            <component-type>uk.co.myco.component.UIDisablePanel</component-type>
        </component>
        <attribute>
            <name>disabled</name>
        </attribute>
    </tag>
</facelet-taglib>

我们正在使用这段代码,一直都能正常工作。但是我发现当我在我的disablePanel中有一个组件,在第一次启用时使用了类似于<p:inputText disabled="#{condition}" />的条件,然后更改该条件并更新整个disablePanel以启用它时,它不会正确地呈现inputText被禁用的状态,而是使用了视图第一次呈现时的初始禁用状态。有什么想法吗? - odaa

2

Omnifaces提供了一个massAttribute标签处理器,其中包含多个选项。最接近您需要的选项是

<o:massAttribute name="disabbled" value="true" target="javax.faces.component.UIInput">
    <h:outputLabel for="input1" />
    <h:inputText id="input1" />
    <h:outputLabel for="input2" />
    <h:inputText id="input2" />
    <h:outputLabel for="input3" />
    <h:inputText id="input3" />
</o:massAttribute>

这将禁用所有继承自javax.faces.component.UIInput的组件。


0

这是一种禁用页面上所有组件的解决方案。请注意,使用此方法,您也可以一次性禁用一组组件。

我将disableUIComponent方法放在一个实用类中,因为我想在多个JSFBean中使用它。

public class UtilsPrimefaces { 

/**
 * Disable all the children components
 * @param uiComponentName
 */
public static void disableUIComponent(String uiComponentName) {  
    UIComponent component = FacesContext.getCurrentInstance()  
            .getViewRoot().findComponent(uiComponentName);
    if(component!=null) {
        disableAll(component.getChildren());
    } 
}  

/**
 * Recursive method to disable the list
 * @param components Widget PD list
 */
private static void disableAll(List<UIComponent> components) {  

    for (UIComponent component : components) {  
        logger.info(component.getClass().getTypeName());            

        if (component instanceof InputText) {  
            ((InputText) component).setDisabled(true);

        } else if (component instanceof InputNumber) {  
            ((InputNumber) component).setDisabled(true);

        } else if (component instanceof InputTextarea) {  
            ((InputTextarea) component).setDisabled(true);

        }  else if (component instanceof HtmlInputText) {  
            ((HtmlInputText) component).setDisabled(true);

        }  else if(component instanceof SelectOneMenu) {  
            ((SelectOneMenu) component).setDisabled(true);

        } else if(component instanceof SelectBooleanCheckbox) {  
            ((SelectBooleanCheckbox) component).setDisabled(true);

        } else if(component instanceof CommandButton) {  
            ((CommandButton) component).setDisabled(true);              
        }
        disableAll(component.getChildren());  
    }  
} 

然后你可以在你的bean中使用。这是一个页面的示例,该页面有3个scrollPanel,我只想禁用panel1和panel3:

@PostConstruct
public void init() {        
    super.init();
    if(userHasPermissions() || loadPageInReadOnly()) {
         Utils.disableUIComponent(":form:panel1");
         Utils.disableUIComponent(":form:panel3");
    }
}

这对我有效 :) 附言:我使用的是primefaces 2.2


1
谢谢。对于每个JSF的新版本,请查看http://showcase.omnifaces.org/taghandlers/massAttribute,它可以完全实现此功能,而且更加灵活,无需编写自己的代码... - Kukeltje

0

Tomahawk的大多数组件都有displayValueOnly、visibleOnUserRole和enabledOnUserRole属性来控制元素的可见性。

希望以下链接对您有用:


-1
如果您想监控性能,请使用JQuery。使用表单中所有元素的prop属性将disabled属性设置为true。
$(document).ready(function(){
        $("#formName :input").prop("disabled", true);
    });

在这里,您还可以使用后备bean的布尔属性。例如

$(document).ready(function(){
        if(#{bean.property} === true)
        $("#formName :input").prop("disabled", true);
    });

可以在客户端进行操作和覆盖。需要有服务器端的对应部分。 - Kukeltje

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接