JSF 2.0: Rendre les champs de formulaire avec les données initiales en utilisant les haricots scope demande (pour mettre à jour les données de serveur spécifique au composant en cours)

StackOverflow https://stackoverflow.com/questions/3812685

Question

Un cas assez normal:

Nous avons une composante composite « portlet » qui a deux états: développée et réduite. Portlets commencent aussi augmenté, mais l'utilisateur peut les réduire en cliquant dessus. Cet état doit être enregistré à la session, de sorte qu'une fois l'utilisateur actualise la page ou accède à une nouvelle, les portlets se rappeler si elles sont déplient / replient.

Ceci est le cœur du problème : Comment voulez-vous mettre en œuvre effectivement cet état d'économie dans un composant, qui peut être inséré à la page plusieurs fois

Quelques arrière-plan / idées:

Mise en œuvre d'économie d'Etat pour un portlet serait facile à réaliser en utilisant un haricot scope session. nombre fixe également de portlets pourrait être pris en charge par la création d'un nombre fixe de haricots scope session, ou déclarer des propriétés différentes en un seul grain. Cependant, je ne veux pas parler même pourquoi ces approches est mauvaise.

Mon idée initiale de c'était de créer une carte (ou une structure d'objet) sous bean session unique de tenir les États pour tous les portlets. Cependant, je ne peux pas se référer directement à ces données de JSF (JSF afin que les mettrait à jour aussi). Je considérais l'écriture d'un getter / setter spécifique pour récupérer / mettre à jour la juste valeur sur la carte, mais ce n'est pas possible car il n'y a pas de données d'identification lors de l'exécution des accesseurs.

Cependant, il est probablement clair que je dois enregistrer les états dans un bean session. Je peux faire l'état d'économie assez facilement en affichant un formulaire avec f:ajax et l'exécution d'une méthode spéciale utilisant listener et les données soumises. Afin de soutenir plusieurs instances de composants, je puisse utiliser (plusieurs instances d'un bean) scope demande à gérer chaque agrandir / réduire. Toutefois, afin d'afficher réellement les données qui identifie le portlet et son état, je dois d'abord l'insérer sur les champs de formulaire en temps de rendu.

Alors, comment fournir effectivement chaque portlet avec des données à droite sur le temps de rendu (en fait juste valeur booléenne / ENUM état dans ce cas, mais envisager un cas où doivent être traitées plus de données)?

Il semble que:

  • h:inputHidden et h:inputText ne prennent pas en charge la mise en valeur initiale autre que la valeur de l'attribut (qui indiquerait #{portletBean.portletState}).
  • Je ne peux pas charger automatiquement la demande des haricots avec des valeurs initiales droit sur leur temps de création, car il n'y a pas d'informations d'identification disponibles.

Encore une fois, il se sent comme je manque quelque chose ... pointeurs?

Je suppose au moins une des réponses serait d'utiliser UIComponent plutôt que des composants composites, mais je voudrais garder ce en tant que composant composite, car il contient beaucoup d'éléments HTML brut.

Mise à jour:

  • Il y a un assez similaire question , avec suggestion d'utiliser haricots scope vue. Je ne pense pas que ce soit ici viable, cependant.
Était-ce utile?

La solution 3

J'ai utilisé un précédemment résolu entaille pour appeler une méthode de haricot de JS :

Création d'un vide, forme invisible, avec h:commandButton et f:ajax à l'intérieur d'appeler listener.

Création d'un bouton distinct pour le lancement de l'événement expansion / effondrement. A partir de ce bouton lancer javascript procédé, qui anime l'expansion / effondrement et en même temps clique sur le bouton caché à l'intérieur de la forme. Toutes les données nécessaires sont envoyées en utilisant l'attribut listener. Listener vise un haricot de session, qui vérifie / met à jour une carte des états, identifiés par les numéros de client de composants.

Ceci est assez simple, se demander pourquoi je ne le savais pas eariler ...

Cependant, il est encore loin d'être parfait et il ne répond pas à la façon dont les grains scope demande-pourraient être initiées avec des valeurs par défaut pour les utiliser comme stockage / forme de transport.

Autres conseils

Je suis arrivé quelques hacks possibles pour cela. Je les poster ici, mais je ne pense pas que ce sont vraiment la voie à suivre:

Utilisez javascript pour définir des champs de formulaire avec les bonnes données directement après avoir rendu:

window.addEvent('domready', function() {
    var portletState = '#{portletBean.getPortletState(cc.attrs.clientId)}';
    // find the field and set the data...
});

Sent veery aki. Je ne veux pas prendre cette route.

Utilisez la carte d'attribut de composant pour contenir les données:

<cc:interface>
    <cc:attribute name="portletState" default="#{portletBean.getPortletState(cc.attrs.clientId)}" />
</cc:interface>

Access à partir du code:

public void stateChangedCallback(String clientId) {
    UIComponent component = FacesContext.getCurrentInstance().getViewRoot().findComponent(clientId);
    String state = (String) component.getAttributes().get("portletState");
}

ne se sent pas bien. Aussi je ne sais pas si cela fonctionne (vous pouvez réellement utiliser EL en défaut attribut).

Utilisez la carte de l'attribut de composant pour contenir les données en fournissant lorsque vous appelez le composant:

<portlet:portlet id="specificPortlet">
    <f:attribute name="portletState" value="#{portletBean.getPortletState(component.clientId)}" />
</portlet:portlet>

Encore une fois, très maladroit et les doublons de votre code.

Vous pouvez le faire en utilisant taglibs, vous pouvez passer des paramètres en balises:

Ajoutez ce qui suit à votre taglib:

<tag>
    <tag-name>date</tag-name>
    <source>components/date.xhtml</source>
</tag>

Alors voici le contenu des composants / date.xhtml

<ui:composition name="date_template">
    <h:panelGrid id="#{id}Panel" columns="1" border="0" cellpadding="0" cellspacing="0">
        <rich:calendar immediate="true" id="#{id}" popup="true" datePattern="dd.MM.yyyy"
                        enableManualInput="true" showApplyButton="true" cellWidth="12px" cellHeight="11px" style="width:100px"
                        value="#{dateForm.date}" required="#{required}" readonly="#{readonly}" validator="#{dateForm.validateDate}">
            <a4j:support event="onchanged" reRender="#{id}Panel,#{reRenderDate}"/>
            <ui:insert />
        </rich:calendar>

        <rich:message for="#{id}" errorClass="error" />
    </h:panelGrid>
</ui:composition>

Et vous utilisez cela comme:

<adse:date id="dateTransfert" required="true"
           dateForm="#{dossierBean.dateTransfert}"
           readonly="false" reRenderDate="montantAncien,montantNouveau,montantEmolument">
     <a4j:support event="oninputblur" reRender="dateTransfertPanel,montantAncien,montantNouveau,montantEmolument"/>
</adse:date>

Dans ce cas, DateForm est transmis, c'est un objet, et dans la taglib nous utilisons les propriétés de cet objet (dateForm.date). Notez également le. qui peut être utilisé pour inclure d'autres éléments dans le XHTML

Alors, vous pouvez passer dans le contexte pour chaque portlet. Vous pouvez même faire cette norme en ayant portletBean comme une superclasse qui définit la méthode getPortletState ().

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top