2017-05-23 6 views
0

私はJSFの動作と混同していますので、ここにMCVEを投稿してください。 私がいるindex.xhtml持っている:Primefaces selectBooleanCheckbox値がAjaxアクションで失われました

<h:form id="entityForm" enctype="multipart/form-data" styleClass="entityForm"> 
<p:dataTable id="dataTableId1" value="#{testBean.testEntityList}" var="tent" rowKey="#{tent.id}"> 
    <p:column style="width:16px"> 
     <p:rowToggler/> 
    </p:column> 
    <p:column> 
     <h:outputText value="#{tent.id}"/> 
    </p:column> 
    <p:column> 
     <h:outputText value="#{tent.name}"/> 
    </p:column> 
    <p:rowExpansion> 
     <p:selectBooleanCheckbox value="#{tent.something}"/> 
     <p:inputText value="#{tent.strNextToSomethingCheckBox}" /> 
    </p:rowExpansion> 
</p:dataTable> 
<p:commandButton id="button1" ajax="true" value="Do something" update="entityForm"/> 
</h:form> 

Beanコード:

@ManagedBean(name = "testBean") 
@ViewScoped 
public class TestBean implements Serializable { 

private static final Logger LOG = Logger.getLogger(TestBean.class); 

private List<TestEntity> testEntityList; 

@PostConstruct 
public void init() { 
    LOG.debug("init call"); 
    testEntityList = new ArrayList<>(); 

    testEntityList.add(new TestEntity(1L, "Entry 1", true, "Value 1 str")); 
    testEntityList.add(new TestEntity(2L, "Entry 2", false, "Value 2 str")); 
    testEntityList.add(new TestEntity(3L, "Entry 3", false, "Value 3 str")); 

} 

public class TestEntity { 

    Long id; 

    String name; 

    Boolean something; 

    String strNextToSomethingCheckBox; 


    public TestEntity(Long id, String name, Boolean something, String strNextToSomethingCheckBox) { 
     this.id = id; 
     this.name = name; 
     this.something = something; 
     this.strNextToSomethingCheckBox = strNextToSomethingCheckBox; 
    } 

    public Long getId() { 
     return id; 
    } 

    public void setId(Long id) { 
     this.id = id; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public Boolean getSomething() { 
     return something; 
    } 

    public void setSomething(Boolean something) { 
     LOG.debug("setSomething call"); 
     this.something = something; 
    } 

    public String getStrNextToSomethingCheckBox() { 
     return strNextToSomethingCheckBox; 
    } 

    public void setStrNextToSomethingCheckBox(String strNextToSomethingCheckBox) { 
     LOG.debug("setStrNextToSomethingCheckBox call"); 
     this.strNextToSomethingCheckBox = strNextToSomethingCheckBox; 
    } 
} 


public List<TestEntity> getTestEntityList() { 
    return testEntityList; 
} 

public void setTestEntityList(List<TestEntity> testEntityList) { 
    this.testEntityList = testEntityList; 
} 

} 

シナリオ:あなたが開いているページ、あなたがボタンを押すと、フォームがあり、確認として、あなたは、チェックボックスの状態が表示されます、最初の行を拡大します更新されたチェックボックスはチェックされています(それを見るには再度行を展開する必要があります)

問題のシナリオ:開いているページ、開いているページ、行を展開しない、ボタンをクリックする、フォームが更新された後、値は真から偽に設定されます

質問:値がtrueからfalseに設定されるのはなぜですか?このバグや予想される動作ですか?どうすればこの問題を回避できますか?おかげさまで あなたはSelectBooleanCheckboxRenderer#decodeコードの下にprimefacesを参照することができます

+0

'h:form'から' enctype = "multipart/form-data" 'を削除するとどうなりますか? – Kukeltje

+0

@Kukeltjeと同じ値が失われ/ falseにリセットされます – jNick

答えて

0

:rowExpansion近い:

@Override 
public void decode(FacesContext context, UIComponent component) { 
    SelectBooleanCheckbox checkbox = (SelectBooleanCheckbox) component; 

    if(checkbox.isDisabled()) { 
     return; 
    } 

    decodeBehaviors(context, checkbox); 

    String clientId = checkbox.getClientId(context); 
    String submittedValue = (String) context.getExternalContext().getRequestParameterMap().get(clientId + "_input"); 

    if(submittedValue != null && isChecked(submittedValue)) { 
     checkbox.setSubmittedValue(true); 
    } 
    else { 
     checkbox.setSubmittedValue(false); 
    } 
} 

pがときp:selectBooleanCheckboxRequestParameterMapに設定されていないため、値をtrueからfalseに設定されている理由はあります。したがって、p:selectBooleanCheckboxがデコードされた場合、submittedValueはnullになります。したがって、checkbox.setSubmittedValue(false)を実行してください。

p:rowExpansionを展開すると、p:selectBooleanCheckboxの値がRequestParameterMapにあることがわかります。 p:selectBooleanCheckboxはそれがオフになっているRequestParameterMapにないセットもあること

public void doSomething() { 
    FacesContext context = FacesContext.getCurrentInstance(); 
    Map<String, String> requestParameterMap = context.getExternalContext().getRequestParameterMap(); 
    Set<String> keySet = requestParameterMap.keySet(); 

    for (String key : keySet) { 
     LOG.debug("key>>" + key); 
     LOG.debug("value>>" + requestParameterMap.get(key)); 
    } 
} 

注: あなたは豆でフォローの方法でp:commandButtonaction="#{testBean.doSomething}"を追加することでこれを確認することができます。 p:selectBooleanCheckboxがオフになっていると、レンダリングされた場合にのみ値がfalseになります。この道を

if (submittedValue != null && isChecked(submittedValue)) { 
    checkbox.setSubmittedValue(true); 
} else { 
    if (checkbox.isRendered()) { 
     checkbox.setSubmittedValue(false); 
    } 
} 

:これまで

if(submittedValue != null && isChecked(submittedValue)) { 
    checkbox.setSubmittedValue(true); 
} 
else { 
    checkbox.setSubmittedValue(false); 
} 

あなたはSelectBooleanCheckboxRenderer#decodeをoveridingし、これをchagingことで、この問題を回避することができます。

EDIT:

ごめんなさい。私のオーバーライドソリューションは、が間違っていますが、考え方はSelectBooleanCheckboxRenderer#decodeを上書きする必要があります。

正しいコードがあれば投稿します。

EDIT 2:

はので、私は別のアプローチを試してみましたSelectBooleanCheckboxRenderer#decodeをオーバーライドすることでそれを動作させるように見えることはできません。

私は、TestEntityにinitの値がfalseのフラグ(トグル)を追加しました。 p:selectBooleanCheckboxp:rowExpansionにレンダリングするフラグとして使用されます。
このフラグは、Bean内でp:ajax event="rowToggle"およびonRowToggleメソッドを使用して行を切り替えたとき(VISIBLE)にtrueに設定されます。

p:selectBooleanCheckboxがレンダリングされていない場合、SelectBooleanCheckboxRenderer#decodeは実行されません。 これにより、値が保持されます。この方法はではないは、SelectBooleanCheckboxRenderer#decodeを上書きする必要があります。ここで

は、コードは次のとおりです。

XHTML:

<h:form id="entityForm" enctype="multipart/form-data" styleClass="entityForm"> 
<p:dataTable id="dataTableId1" value="#{testBean.testEntityList}" var="tent" rowKey="#{tent.id}"> 

    <p:ajax event="rowToggle" listener="#{testBean.onRowToggle}"/> 

    <p:column style="width:16px"> 
     <p:rowToggler/> 
    </p:column> 
    <p:column> 
     <h:outputText value="#{tent.id}"/> 
    </p:column> 
    <p:column> 
     <h:outputText value="#{tent.name}"/> 
    </p:column> 
    <p:rowExpansion> 
     <p:selectBooleanCheckbox value="#{tent.something}" rendered="#{tent.toggled}"/> 
     <p:inputText value="#{tent.strNextToSomethingCheckBox}" /> 
    </p:rowExpansion> 
</p:dataTable> 
<p:commandButton id="button1" ajax="true" value="Do something" update="entityForm"/> 
</h:form> 

がBean:

@ManagedBean(name = "testBean") 
@ViewScoped 
public class TestBean implements Serializable { 

    private static final Logger LOG = Logger.getLogger(TestBean.class); 

    private List<TestEntity> testEntityList; 

    @PostConstruct 
    public void init() { 
     LOG.debug("init call"); 
     testEntityList = new ArrayList<>(); 

     testEntityList.add(new TestEntity(1L, "Entry 1", true, "Value 1 str", false)); 
     testEntityList.add(new TestEntity(2L, "Entry 2", false, "Value 2 str", false)); 
     testEntityList.add(new TestEntity(3L, "Entry 3", false, "Value 3 str", false)); 
    } 

    public class TestEntity { 

     Long id; 

     String name; 

     Boolean something; 

     String strNextToSomethingCheckBox; 

     boolean toggled; 

     public TestEntity(Long id, String name, Boolean something, String strNextToSomethingCheckBox, boolean toggled) { 
      this.id = id; 
      this.name = name; 
      this.something = something; 
      this.strNextToSomethingCheckBox = strNextToSomethingCheckBox; 
      this.toggled = toggled; 
     } 

     // getters and setters 
    } 

    public List<TestEntity> getTestEntityList() { 
     return testEntityList; 
    } 

    public void setTestEntityList(List<TestEntity> testEntityList) { 
     this.testEntityList = testEntityList; 
    } 

    public void onRowToggle(ToggleEvent event) { 
     TestEntity entity = (TestEntity) event.getData(); 

     if (event.getVisibility() == Visibility.VISIBLE) { 
      entity.setToggled(true); 
     } else { 
      entity.setToggled(false); 
     } 
    } 
} 

この情報がお役に立てば幸いです。

関連する問題