lunedì 23 aprile 2012

Wicket - Link ereditati e non completi

Può capitare di aver bisogno di settare qualche parametro su un LINK o un comportamento su cui però non abbiamo potere perché ereditato da una libreria.

Mi è infatti capitato di ereditare infatti un oggetto imgLinkColumn che creava una colonna per una tabella dove al suo interno c'era una immagine con un link.

L'oggetto funzionava se non fosse che la persona che l'ha creata, non ha parametrizzato l'oggetto dandogli la possibilità, per esempio, di decidere il target del link.

Normalmente se si estende l'oggetto LINK di Wicket, anche ai livelli più bassi di estensione ho comunque a disposizione i metodi della classe originale over compare il setTarget.

In questo caso però la classe originale di partenza era una PropertyColumn che tutto ha fuorché una setTarget visto che il suo scopo è quello di riempirsi con una proprietà associata.

Chi ha esteso questa classe creando appunto la imgLinkColumn ha creato dentro di se il Link ma non lo ha dotato dei metodi del LINK originale.

public AbstractLink createLink(final String componentId, final IModel<T> model) {
        Link<T> link = new Link<T>("link") {
            private static final long serialVersionUID = 1L;

            @Override
            public void onClick() {
                HTMLLinkColumn.this.onClick(componentId, model);
            }
        };
        
        link.setPopupSettings(popupSettings);

        return link;
    }

Come fare quindi a creare un link con target = _blank?

La soluzione è fare Override di questa createLink.


@Override
            public AbstractLink createLink(String componentId,
                    IModel<DittaSearchResult> model) {
                 AbstractLink a = super.createLink(componentId, model);
                 a.add(new AbstractBehavior(){
                    private static final long serialVersionUID = 1L;
                    @Override
                    public void onComponentTag(Component component,
                            ComponentTag tag) {
                         tag.put("target", "_blank");
                    }
                 });
                 return a;
            }

In questo modo stiamo imponendo la chiamata al nostro metodo che alla sua renderizzazione, lancerà la onComponentTag.

La classe AbtrasctBehavior ci serve per poter associare all'oggetto LINK un evento. Purtroppo l'oggetto ci viene dato già fatto dalla superclasse e su quello NON abbiamo potere. Benché infatti l'oggetto LINK di Wicket abbia il metodo onComponentTag (come la maggiorparte degli oggetti Wicket di elementi HTML) non possiamo lanciarlo perché noi siamo prendendo l'oggetto già fatto.

L'unico modo per sovrascrivere quello che ci viene dato, è agganciarci a mano un BEHAVIOR nella quale diciamo di aggiungere il parametro target="_blank" quando l'elemento è renderizzato.

ESTENDERE


L'altro modo per risolvere il problema alla radice prevede di estendere direttamente la classe originale sovrascrivendo così la createLink fallata.

public TargettableImgLinkColumn(IModel<String> displayModel, ResourceReference resourceReference, final String target) {
        super(displayModel, resourceReference);
        this.target = target;
    }

Creiamo quindi un nuovo costruttore che preveda un terzo parametro ovvero il target. Nell'esempio gli altri due parametri sono quelli del costruttore che stiamo ereditando. Uno è il modello e l'altro è il riferimento alla risorsa immagine.

A questo punto abbiamo il nostro target in una proprietà privata interna alla classe. Occorre ora sovrascrivere la createLink che stavamo ereditando.

public AbstractLink createLink(String componentId,IModel<T> model) {
         AbstractLink a = super.createLink(componentId, model);
         a.add(new AbstractBehavior(){
            private static final long serialVersionUID = 1L;
            @Override
            public void onComponentTag(Component component,
                    ComponentTag tag) {
                 tag.put("target", TargettableImgLinkColumn.this.getTarget());
            }
         });
         return a;
    }

 Come vediamo, abbiamo sovrascritto il metodo in maniera analoga a quanto avevamo fatto sopra. L'unica differenza riguarda il fatto che il parametro target lo prendiamo dalla classe stessa.
Da notare che essendo la classe Abstract creata internamente, non può avere scope diretto della proprietà target. Non potevo quindi scrivere semplicemente this.target. La cosa più pulita da fare quindi era prenderla dall'istanza della classe stessa (espressa da this) dentro cui mi stanno dichiarando. Il metodo getTarget() è invece il semplice metodo get della proprietà.

Nessun commento:

Posta un commento