1

I encounter an issue where I use one of my inner classes in an apex:attribute of a VisualForce Component.

Based on this thread: Reference inner class in Visualforce component I refactored my code to work with an interface beside my initial inner class, now I have the following :

My interface :

public interface MyInterface {

    Boolean getOne();
    Boolean getTwo();
}

My class implementing it :

    public class MyImp implements MyInterface {

    public Boolean one{ get; set; }
    public Boolean two { get; set; }

    public Boolean getOne() {
        return one;
    }

    public Boolean getTwo() {
        return two;
    }


}

My component :

<apex:component>
    <apex:attribute name="entry" type="MyInterface " description=""/>
    <!-- Different tests I made -->
    {!entry} <!-- work but got all information on my object -->
    {!entry.getOne()} <!-- does not work -->
    {!entry.one} <!-- does not work -->
    {!entry.getOne} <!-- does not work -->
</apex:component>

Unfortunately, it still does not work, as I cannot use my class properties in my VisualForce Page. I always encounter the issue of Unknown properties or Unknown functions depending on how my component is written.

I'm pretty sure that there is something obvious that I'm missing but I cannot find a solution for this.

Thanks for your help!

1 Answer 1

0

tl;dr

You can't use interfaces this way. You have to use some kind of class.


{!entry.getOne()} <!-- does not work -->

Doesn't work because () can only be used with functions, such as {!LEN(myArray)}.

{!entry.one} <!-- does not work -->

Doesn't work because you end up accessing one and two directly, rather than getOne and getTwo. Interfaces are not called by Visualforce in the same way as classes.

{!entry.getOne} <!-- does not work -->

Won't work unless the method is called as an action, as in:

<apex:commandButton action="{!entry.getOne}" label="Get One" />

But, that, of course, won't have the effect you're looking for. What you want, instead, is an abstract or virtual class, rather than an interface.

public abstract class MyAbstract {
  public abstract Boolean getOne();
  public abstract Boolean getTwo();
}
<apex:component>
  <apex:attribute name="entry" type="MyAbstract" description="" />
  {!entry.one}
</apex:component>
public class MyImpl extends MyAbstract {
    public Boolean m_one;
    public Boolean m_two;
    public override Boolean getOne() {
        System.debug('one');
        return m_one;
    }
    public override Boolean getTwo() {
        System.debug('two');
        return m_two;
    }
}
public class MyController {
    public MyAbstract entry { get; set; }
    public MyController() {
        entry = new MyImpl();
        ((MyImpl)entry).m_one = true;
    }
}

Note that if public Boolean one { get; set; } and public Boolean getOne() both exist in the same class, the method will never be called, as the default getter will be called instead. This is why I chose to use m_one to store the backing data. That said, however, as long as the property doesn't have default getters and setters, the method can still be called. Here's an alternative:

public class MyImpl extends MyAbstract {
    public Boolean one;
    public Boolean two;
    public override Boolean getOne() {
        return one;
    }
    public override Boolean getTwo() {
        return two;
    }
}

Because we removed the { get; set; }, Visualforce now knows that you mean to call getOne when you write {!entry.one}, because the class variable is no longer exposed as a property.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .