3

I currently have a complex but structured object for my visualforce page. The object itself has multiple wrapper objects within itself, currently about 3-4 deep. For example:

public class MyOuterObject{

    public Id accountId { get; set; }
    public String accountName { get; set; }
    public List<Invoice> invoices { get; set; }
    public List<Shipment> shipments { get; set; }
    public Decimal balance { get; set; }

    public MyOuterObject(List<Custom__c> details){
       /* Constructor setup here */
       for(Custom__c c : details){
          balance += c.Balance__c;
          this.invoices.add( new Invoice( c ) );
       }
    }
}

You can see that this would instantiate a list of Shipments as well as Invoices which contain records of their SF custom object, but for the sake of this visualforce page are inner classes of MyOuterObject. In addition each of these inner classes also have an inner class representing their instance's line items (I can add this code as well but don't believe it is necessary at the moment).

So these objects make up the list of outer object that are then iterated on my visualforce page like so:

<apex:repeat value="{!p.invoices}" var="i">
    <!-- Single invoice -->
    <apex:outputPanel layout="block">
        <apex:form >
            <apex:outputPanel layout="block">
                <apex:outputPanel layout="block">Product</apex:outputPanel>
                <apex:outputPanel layout="block">Units</apex:outputPanel>
                <apex:outputPanel layout="block">Unit Cost</apex:outputPanel>
                <apex:outputPanel layout="block">Total Cost</apex:outputPanel>
                <apex:outputPanel layout="block">Units to Pay</apex:outputPanel>
            </apex:outputPanel> <!-- /.header -->

            <apex:repeat value="{!i.invoiceLineItems}" var="lineItem">
                <apex:outputPanel styleClass="i-line" layout="block">
                    <apex:outputPanel layout="block">{!lineItem.record.Product__r.Name}</apex:outputPanel>
                    <apex:outputPanel layout="block">{!lineItem.record.Units_Owed__c}</apex:outputPanel>
                    <apex:outputPanel layout="block">${!lineItem.record.Replacement_Cost__c}</apex:outputPanel>
                    <apex:outputPanel layout="block">${!lineItem.record.Total_Invoiced__c}</apex:outputPanel>

                    <!-- HERE IS THE INPUT FIELD IN QUESTION -->
                    <apex:inputText value="{!lineItem.unitsToPay}" onChange="updateUnitsToPay(this)"/>
                </apex:outputPanel>
            </apex:repeat>

            <apex:outputPanel styleClass="total-line" layout="block">
                <apex:outputPanel layout="block">Remaining Balance</apex:outputPanel>
                <apex:outputPanel layout="block">${!i.balance}</apex:outputPanel>
            </apex:outputPanel>
            <apex:outputPanel styleClass="to-pay" layout="block">
                <apex:outputPanel styleClass="title" layout="block">Amount to Pay</apex:outputPanel>
                <apex:outputPanel layout="block">${!i.payment}</apex:outputPanel>
            </apex:outputPanel>

            <apex:commandButton value="Apply Payment" action="{!processPayment}"></apex:commandButton>

        </apex:form>
    </apex:outputPanel>
</apex:repeat>

As a visual aid this looks like this:

enter image description here

My question simply put is this... How can I capture/set the value of the input field "onChange" of the input field?

At the moment I'm working on an attempt to call an actionFunction through javascript but I'm not sure how I would manually set the value on the "line item" instance and then rerender just that invoice section (if possible)

Also, "onChange" is the ideal interaction I want, but if I use the onchange event to convert the submit button into a "recalculate" button instead than I could do the same logic on a command button, but again there is a question of how I would set the values to the correct line item instances.

Update/Follow up question:

So I don't even see that the setter is firing when I submit the form through a command button. I tested this by setting up a debug on the setter like this:

public class InvoiceLineItem {
    public Decimal unitsToPay { get; set{
        unitsToPay = value;
        System.debug('::VALUE:: '+value);
    } }

    /* Constuctor */
}

I see this print on page load but once I submit the form it rerenders the invoice with its original values and debug shows no trace of setting ever firing.

2

It seems to me that you're going to need to rerender the entire form and will want to create a custom "setter" of sorts that would work much like the return on a custom generated multi-selectOption would (done in a for loop).

<apex:inputText value="{!lineItem.unitsToPay}" onChange="setUnitsToPay(this)" rerender = "theform"/>

There should be plenty of posts around here on how that's done. But here's an example, just in case, here's a stripped down version of some code I once used:

    public void processSelected() {

        for (SelectOption selOption : ClientOptions)
        {   

            if (selOption.getValue() == selectedClient)
            {                   
                clientId = string.valueOf(selectedClient);

            }
        }

        system.debug('----> Entering Selection For Loop to Do Something');

        for (ssOption m:MS) {

            if (m.selected) {
                ..... do something

            }
        }
    }

You'd want to modify this kind of logic (the above was a wrapper object in the select list).

Have it read the values of setUnitsToPay and generate a new list of the values for the lineItem. Assemble the new list of lineItems, send it to your next method and work your way back out. If you change your unitstoPay, the RemainingBalance and AmountToPay will both change. That forces you to have to recalculate everything to get those values.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.