2014-06-23 31 views
5

Bu soru, "kavramsal" veya "JSF'yi anlamıyorum" ifadesinin daha fazlası olabilir. Küme İşlemi için Yasadışı Sözdizimi: JSF'ye nasıl bir setter "istemediğimi" söyleme

Benim senaryo

: Ben kullandığım bir JSF Sayfası ( index.xhtml) bir p:accordionPanel (ama ben ne olduğunu bileşeni bu konularda sanmıyorum). Yapmak istediğim, bunun activeIndexes değerini ayarlamaktır.

<p:accordionPanel multiple="true" activeIndex="#{myController.getActiveIndexesForSections('whatever')}"> 
// bla bla... 
</p:accordionPanel> 

Ve yedekleme fasulye (basitleştirilmiş) yöntemi:

public String getActiveIndexesForSections(String holderName){ 
    String activeSections = ""; 
    for(Section s : sectionMap.get(holderName)){ 
     if (s.isActive()) 
     //add to the string 
    } 
    return activeSections; 
} 

Şimdi bu normal bir sayfa yüklemesinde gayet güzel çalışıyor.

Ama p:commandButton (ajax=false birlikte) tıklayın (veya başka bir şey sanırım sunucuya geri verileri "gönderir") ise - Aşağıdaki özel durum almak: Bazı googling/okumadan sonra

/WEB-INF/tags/normalTextSection.xhtml @8,112 activeIndex="#{myController.getActiveIndexesForSections(name)}": Illegal Syntax for Set Operation 
// bla.. 
Caused by: javax.el.PropertyNotWritableException: Illegal Syntax for Set Operation 

hata mesajı, bir setter ihtiyacım olduğunu buldum.

Her şeyden önce: Ben bir setter istemiyorum - gerçekten ihtiyacım var mı yoksa JSF'ye bu "davranışı" istemediğini söylemenin bir yolu var mı?

İkinci olarak, ayarlamamın "kolay" olması değil, yöntemimin bir parametresi olduğundan (public void setActiveIndexesForSections(String name, String activeIndexes) veya public void setActiveIndexesForSections(String name) çalışmayacak) farkettim. Sonunda geldi ne geçerli:

bir (jenerik) "Sözde Mülk sınıf" oluşturun:

// just a dummy class since the class is recreated at every request 
public class Property<T> implements Serializable { 

    private T val; 

    public Property(T val) { 
     this.val= val; 
    } 

    public T getVal() { 
     return val; 
    } 

      //no need to do anyhting 
    public void setVal(T val) { 
    } 
} 

Değiştir fasulye yöntemi:

public Property<String> getActiveIndexesForSections(String holderName){ 
    String activeSections = ""; 
    for(Section s : sectionMap.get(holderName)){ 
     if (s.isActive()) 
     //add to the string 
    } 
    return new Property<String>(activeSections); 
} 

Ve diyoruz index.xhtml dan: Bu açıkça çalışır ancak

<p:accordionPanel multiple="true" activeIndex="#{myController.getActiveIndexesForSections('whatever').val}"> 
// bla bla... 
</p:accordionPanel> 

wo/çirkin kesmek rkaround.

Böyle bir durumun üstesinden gelmenin doğru yolu nedir? Ya da tamamen yanlış yaptığım şey nedir?

cevap

17

Setter, formun gönderildiği sırada olduğu gibi etkin dizinleri hatırlamak için gereklidir. Temel olarak, onu bir değer ifadesi olarak (bir özellik ile), bir yöntem ifadesi olarak değil (bir eylem yöntemi gibi) veya değiştirilemeyen bir koleksiyon olarak (activeIndex="#{param.tab}" gibi) bağlamanız gerekir. Tam olarak giriş değerlerinde olduğu gibi. Teknik olarak, gerçekten "sadece tamamen yanlış" yapıyorsunuz;)

Gereksinim şu şekilde anlaşılmaktadır. Değişen aktif dizinler ile gerçekten ilgilenmediğiniz ve bu nedenle her formda varsayılanlara sıfırlamak istediğinizi düşündüğünüzde, sonucu <c:set> yardımı ile istek özniteliği olarak saklayarak atlayabilirsiniz. Bu şekilde EL'yi, kasıtlı fasulye özelliği yerine istek özniteliği haritasına ayarlamak için kandırırsınız. Altında kapsayan

<c:set var="activeIndex" value="#{myController.getActiveIndexesForSections('whatever')}" scope="request" /> 
<p:accordionPanel multiple="true" activeIndex="#{activeIndex}"> 
    <!-- bla bla... --> 
</p:accordionPanel> 

, temelde belli ki sadece çalışacaktır setter operasyonu olarak externalContext.getRequestMap().put("activeIndex", value) yapacağız.


Güncelleme: source code of AccordionPanel component teftiş üzerine, ben rendered nitelik false değerlendirir zaman activeIndex ayarlanamaz gerçeği verilen başka geçici çözümü gördük. Bu yüzden tam olarak davranmak için rendered özniteliğini değiştirin: güncelleme modeli değerleri fazı (4. aşama) sırasında false değerini değerlendirin.

<p:accordionPanel multiple="true" 
    activeIndex="#{myController.getActiveIndexesForSections('whatever')}" 
    rendered="#{facesContext.currentPhaseId.ordinal ne 4}"> 
    <!-- bla bla... --> 
</p:accordionPanel> 
+0

Bana merhamet ettiğin için teşekkür ederim;) Bunu yapmak için başka bir yol önerir misin? (İnanamıyorum ki, bu kullanım durumu o kadar nadirdir ki, hiç kimse bunu yapmayı istemedi - bu yüzden büyük resmi anlayamazsam gerçekten endişeliyim ...) - Ayrıca benim 'akordeonPanel' bir parametre olarak 'her ne varsa' bir etiket içinde üretilirler - parametreyi 'c: set' 'den 'var' olarak ve daha sonra 'accordionPanel'nin' activeIndex 'olarak kullanabilir miyim? Öyleyse nasıl? –

+1

Bu özel durumda doğru yol, özel bir 'Harita' uygulamasının geri dönmesi olacaktır. Ve hayır, 'var' özniteliğinde EL kullanamazsınız, bu yüzden bir etiket dosyası bozuk olur. Herhangi bir şekilde, kaynak kodunu inceledikten sonra, etiket dosyalarında daha iyi yeniden kullanılabilen bir başka çözüm gördüm. Cevap güncellemesine bakın. – BalusC

+0

Teşekkürler. Bunu ve yarın 'özel' haritayı da deneyeceğim. Ve eğer + "lütfunu" kabul ederse, o zaman :) –