1

I have a wrapper class within my component controller

public class WrapperClass{

    public Decimal  base        { get; set; }
    public Decimal  goal        { get; set; }
    public String   suffix      { get; set; }
    ...

    public Goal(String suffix, Decimal base, Decimal goal){
        this.suffix = suffix;
        this.base = base;
        this.goal = goal;
    }
}

This is then constructed into a map that is indexed by month like so:

public Map<String,WrapperClass> wrapperItems{ get; set; }

I also have a wrapper class for Month and have a list of those that I <apex:repeat> through in my component like so:

Component:

<apex:repeat value="{!months}" var="month">

<apex:inputText id="myId" value="{!wrapperItems[month.Name].goal}">
    <apex:actionSupport event="onchange" action="{!modifyItem}" rerender="currentSection" status="mypoller">
        <!-- I've attempted passing parameters to get what I need but with no luck -->
        <apex:param name="month" value="{!month.name}"></apex:param>
        <apex:param name="suffix" value="{!wrapperItems[month.Name].suffix}"></apex:param>
    </apex:actionSupport>
</apex:inputText>

</apex:repeat>

NOTE: I'm using actionSupport to do an onChange event, not sure if that would have any effect here, and not sure of another option to get desired interaction

Controller:

public PageReference modifyItem(){
    String month = String.valueOf(ApexPages.currentPage().getParameters().get('month'));
    System.debug('::ITEM:: '+wrapperItems.get(month));
}

I've got getters/setters setup in my wrapper class and for the wrapperItems map, which I found was a common issue for other users. Not sure what else I'm missing here so really appreciate any help that can be offered.

5
  • Is there a reason you don't just add an instance of WrapperClass as a property on Month? Just don't want to inject that dependency?
    – Adrian Larson
    Commented Mar 15, 2016 at 4:34
  • Never really thought to... They are two separate objects it would seem odd to me to put them together. Commented Mar 15, 2016 at 4:37
  • 1
    All I can see is the data structure, so it made me curious. Then you could bind directly (e.g. value="{!month.wrapperInstance.goal}"). You could also make a separate ComboWrapper that has both so it's more natural.
    – Adrian Larson
    Commented Mar 15, 2016 at 4:39
  • Why don't you try with apex:param assignTo="{!wrapper.variable}" for each row ?
    – Ratan Paul
    Commented Mar 15, 2016 at 6:00
  • Instead of apex:actionsupport, you should use on-change event and call action function while passing necessary parameters. Then you may get binded values also.
    – Ankuli
    Commented Mar 15, 2016 at 20:07

2 Answers 2

2

I can't put all this in a comment and I don't have the time/energy to research right now, so hopefully I don't get negged for this answer. Just want to try to explain what I'm getting at.

It looks like you have a one to one relationship in your data structure. For each Month, there is a corresponding Goal wrapper, and vice versa. Try creating some sort of combined wrapper such as MonthlyGoal:

public class MonthlyGoal
{
    public Month month { get; private set; }
    public Goal goal { get; private set; }
}

Then, you can just repeat through a List<MonthlyGoal> and bind directly, instead of trying to set a map element. I'm not sure if the latter is possible as I've never tried it.

<apex:repeat value="{!monthlyGoals}" var="monthlyGoal">
    <apex:outputText value="{!monthlyGoal.month.Name}" />
    <apex:inputText value="{!monthlyGoal.goal.goal}" />
</apex:repeat>
2
  • 1
    I appreciate this tip for how much cleaner my code looks and works, but I'm still not getting a new value. Markup looks like this: <apex:inputText value="{!i.goal.value}"> Then within pagereference method I have this debug System.debug('m.month.name+': '+m.goal.value); but still get original set value Commented Mar 16, 2016 at 3:58
  • 1
    Using <apex:actionfunction> I was finally able to get the new value passed through a parameter but I can't manually set it for some reason it doesn't work. I passed the index and new value from the action function and I attempt to set with this monthlyGoals[index].goal.setGoal(goal) and debug of setGoal() shows the new value but when the monthlyGoals List is not modified. I guess I figured it would be "pass-by" referenced... Commented Mar 16, 2016 at 5:34
1

Based on the hint from @Ankuli in the comments I went ahead with the <apex:actionfunction> approach. This solved part of my problem by at least allowing me to send parameters of my newly input data, but I still had an issue with "setting" the values... or so I thought.

In case you don't realize this already, component constructors happen PRIOR to GETTERS/SETTERS being established, so if your constructor relies on any of these, good luck! At least with VF pages when you have an issue in the context of the constructor (for example DML and Platform Cache attempts), you can use the action="{!init}" attribute/approach.

With these things to consider, basically this leaves you with hooking into a setter so that you can execute an "init" method to build out what you need. For example:

public String someVar { get; 
    set{
        init();
    } 
}

Followed by your init(), keep in mind that on pageReferences and anything else that hits your setters, this will fire again unless you prevent it with some come counter/boolean variable:

void init(){
    this.var1 = '';
    this.var2 = (var2==NULL) ? '1' : var2;
}

Also here is a quick summary of my use of the actionFunction implementation:

Repeat Fields:

<apex:repeat value="{!myList}" var="i">
    <apex:outputPanel id="rowOfMyList" styleClass="row field-row" layout="block">
        <apex:inputText id="inputId" value="{!i.obj.value}" html-data-index="{!i.obj.index}" html-data-render="{!$Component.rowOfMyList}" onChange="updateField(this)"/>
    </apex:outputPanel>
</apex:repeat>

JS Script:

function updateField(row) {
    myActionFunction(row.getAttribute('data-index'), row.value, row.getAttribute('data-render'));
}

Action Function:

<apex:actionFunction action="{!pageRefMethod}" name="myActionFunction" rerender="{!renderRow}" >
    <apex:param name="index" value=""/>
    <apex:param name="goal" value=""/>
    <apex:param name="render" assignTo="{!renderRow}" value=""/>
</apex:actionFunction>

You must log in to answer this question.

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