How to prevent multiple composite components reset themselves on a JSF page?

前端 未结 1 1664
甜味超标
甜味超标 2020-12-18 09:32

I put this problem in a simple example, a composite component that calculates the sum of 2 inputs and prints the result in an outputText

Main JSF page:



        
1条回答
  •  一整个雨季
    2020-12-18 10:18

    UIComponent instances are recreated on every request, hereby losing all instance variables everytime. They basically act like request scoped managed beans, while you intend to have them in the view scope. You need to take view state saving into account on a per-attribute basis. This is normally by default already done for all attributes of #{cc.attrs}. So, if you can, just make use of it:

    
        
        
    
    
        
             
            
             
        
        
    
    

    with just this (nullchecks omitted; I recommend to make use of required="true" on the inputs)

    @FacesComponent("calculator")
    public class Calculator extends UINamingContainer {
    
        public void sum() {
            Long firstNumber = (Long) getAttributes().get("firstNumber");
            Long secondNumber = (Long) getAttributes().get("secondNumber");
            getAttributes().put("result", firstNumber + secondNumber);
        }
    
    }
    

    Otherwise, you'd have to take state saving into account yourself by delegating all attribute getters/setters to UIComponent#getStateHelper(). Based on the very same Facelets code as you have, the entire backing component would look like this:

    @FacesComponent("calculator")
    public class Calculator extends UINamingContainer {
    
        public void sum() {
            setResult(getFirstNumber() + getSecondNumber());
        }
    
        public void setFirstNumber(Long firstNumber) {
            getStateHelper().put("firstNumber", firstNumber);
        }
    
        public Long getFirstNumber() {
            return (Long) getStateHelper().eval("firstNumber");
        }
    
        public void setSecondNumber(Long secondNumber) {
            getStateHelper().put("secondNumber", secondNumber);
        }
    
        public Long getSecondNumber() {
            return (Long) getStateHelper().eval("secondNumber");
        }
    
        public void setResult(Long result) {
            getStateHelper().put("result", result);
        }
    
        public Long getResult() {
            return (Long) getStateHelper().eval("result");
        }
    
    }
    

    See, no local variables anymore. Note that I also removed the need for those ugly manual String-Long conversions by just declaring the right getter return type and setter argument type. JSF/EL will do the conversion automagically based on default converters or custom Converters. As there's already a default one for Long, you don't need to provide a custom Converter.


    Unrelated to the concrete problem, you can safely remove the getFamily() method. The UINamingContainer already provides exactly this. If you were implementing NamingContainer interface instead, then you'd indeed need to provide it yourself, but this is thus not the case here. The above backing component examples have it already removed.

    0 讨论(0)
提交回复
热议问题