1

I am attempting to update the total of a line item in a pageblock table with javascript and cannot seem to get this to work properly.

<script>
    function calculateTotal(qtyId, salePriceId, discnt, totalId)
    {
        var q = document.getElementById(qtyId).value;   
        var sp = document.getElementById(salePriceId).value;
        var d = document.getElementbyId(discntId).value;       
        var tp = q(sp-sp*d)  
        document.getElementById(totalId) = tp;
    }
</script>

<apex:column headerValue="{!$ObjectType.OrderItem.Fields.Quantity.Label}">
     <apex:inputField value="{!s.Quantity}" id="qty" style="width:40px" required="false" onkeyup="{calculateTotal}"/>
</apex:column>

<apex:column headerValue="{!$ObjectType.OrderItem.Fields.Discount__c.Label}">
      <apex:inputField value="{!s.Discount__c}" id="discnt" style="width:40px" required="false" onkeyup="{calculateTotal}"/>
</apex:column>

<apex:column headerValue="Sales Price">
     <apex:inputField value="{!s.UnitPrice}" id="salePrice" style="width:80px" required="false" onkeyup="{calculateTotal}"/>
</apex:column>

<apex:column headerValue="Total">
     <apex:OutputText id="total" style="width:80px"/>
</apex:column>
  • 1
    It looks like there are quite a few problems. A place to start is to have the JavaScript console of your browser visible so you can see the JavaScript errors - see e.g. How do I start to debug my own Visualforce/JavaScript?. Hopefully people will post specific changes too. – Keith C Jun 13 '14 at 16:47
  • Start by fixing this line: document.getElementById(totalId) = tp;. I don't know the salesforce template language, but you aren't setting text into a field with that above line (that would likely just generate an error). – jfriend00 Jun 13 '14 at 16:50
  • Thanks Keith! That is helpful, but I do not know enough about javascript to debug it. – Liz Jun 13 '14 at 18:01
  • 1
    ... well it looks like today is the day to start finding out more about JavaScript then. Or you could solve your problem using some other technique e.g. Visualforce's re-rerendering. – Keith C Jun 13 '14 at 18:10
  • Note also that the id= attribute on a VF component is not directly referenceable 'asis' within Javascript because SFDC expands the id you enter into something guaranteed to be unique. See salesforce.com/us/developer/docs/pages/Content/… – cropredy Jun 14 '14 at 0:39
2

You can avoid having to explicitly define javascript functions on the page completely. Simply use the action support tag with your input fields to re-render the total column value for that row, like so:

<apex:pageBlockTable value="{!lines}" var="line" >
    <apex:column headerValue="Quantity">
        <apex:actionRegion >
            <apex:inputField value="{!line.Quantity__c}">
                <apex:actionSupport event="onkeyup" reRender="total"/>
            </apex:inputField>
        </apex:actionRegion> 
    </apex:column>
    <apex:column headerValue="Discount">
        <apex:actionRegion >
            <apex:inputField value="{!line.Discount__c}">
                <apex:actionSupport event="onkeyup" reRender="total"/>
            </apex:inputField>
        </apex:actionRegion> 
    </apex:column>
    <apex:column headerValue="Unit Price">
        <apex:actionRegion >
            <apex:inputField value="{!line.Unit_Price__c}">
                <apex:actionSupport event="onkeyup" reRender="total"/>
            </apex:inputField>
        </apex:actionRegion>    
    </apex:column>
    <apex:column headerValue="Total">
        <apex:outputText id="total" value="{0, number, 0.00}">
            <apex:param value="{! line.Quantity__c * (line.Unit_Price__c - line.Unit_Price__c * line.Discount__c) }"/>
        </apex:outputText>
    </apex:column>  
</apex:pageBlockTable>

Note that I have also and action regions to make sure only the fields that are changed are updated in the view state.

  • Thank you Christopher. I was able to get this to work partially. I was on with SF Dev Support trying to get the rest working, but they couldn't come up with a resolution. I got the Total to populate perfectly, but I need to also have the Sales Price field rerender if there is a discount. They said that this would have to be done with javascript and could not provide support for that. Do you have any ideas? – Liz Jun 19 '14 at 10:31
2

Below is some code that does what I think you want.

Visualforce generates unique IDs for each field based on the nesting of the apex: tags and in a table also adds a row number. Expressions like {!$Component.q} automatically expand to these ID values and result in a JavaScript call of this form per input field (with the quotes needed to make the values valid JavaScript strings):

onkeyup="calculateTotal(
        'j_id0:j_id1:j_id2:j_id3:0:q',
        'j_id0:j_id1:j_id2:j_id3:0:d', 
        'j_id0:j_id1:j_id2:j_id3:0:p',
        'j_id0:j_id1:j_id2:j_id3:0:t'
        )"

The calculateTotal JavaScript can then uses standard Document Object Model (DOM) methods and attributes to obtain values from the page and set values in the page.

When the page opens, the totals are calculated using a Visualforce expression because it would be awkward with this approach to run the JavaScript to do the calculation at that point.

If you think you are going to be doing a lot of this sort of code or more complicated code then it would be worth using the jQuery library. This allows JavaScript code to be hooked up in a page based on powerful HTML element selectors and so results in cleaner and more flexible code.

<apex:page controller="MyController">
<apex:form>
<apex:pageBlock>
<apex:pageBlockTable value="{!lines}" var="s">

<apex:column headerValue="Quantity">
    <apex:inputField value="{!s.Quantity__c}" id="q" style="width:40px" required="false"
        onkeyup="calculateTotal('{!$Component.q}', '{!$Component.d}', '{!$Component.p}', '{!$Component.t}')"/>
</apex:column>
<apex:column headerValue="Discount">
    <apex:inputField value="{!s.Discount__c}" id="d" style="width:40px" required="false"
        onkeyup="calculateTotal('{!$Component.q}', '{!$Component.d}', '{!$Component.p}', '{!$Component.t}')"/>
</apex:column>
<apex:column headerValue="Unit Price">
    <apex:inputField value="{!s.UnitPrice__c}" id="p" style="width:80px" required="false"
        onkeyup="calculateTotal('{!$Component.q}', '{!$Component.d}', '{!$Component.p}', '{!$Component.t}')"/>
</apex:column>
<apex:column headerValue="Total">
    <apex:outputText id="t" style="width:80px" value="{0, number, 0.00}">
        <apex:param value="{! s.Quantity__c * (s.UnitPrice__c - s.UnitPrice__c * s.Discount__c / 100) }"/>
    </apex:outputText>
</apex:column>

</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>

<script>
function calculateTotal(qId, dId, pId, tId) {
    var q = document.getElementById(qId).value;
    var d = document.getElementById(dId).value;  
    var p = document.getElementById(pId).value;     
    var t = q * (p - p * d / 100);
    document.getElementById(tId).innerHTML = t.toFixed(2);
}
</script>
</apex:page>

PS Christopher Alun Lewis's answer is a great example of how the platform's built-in facilities can save you from complications such as having to write JavaScript and leave you with a much more maintainable solution. The difference is in how fast the page updates: the JavaScript approach gives instantaneous updates whereas the re-render approach requires a round-trip back to the server with all the view state which can take several seconds.

  • Thanks Keith. Unfortunately I was not able to get this to work. Like I said, I have very little experience with javascript (one or two classes in college YEARS ago). I do appreciate the response though. Salesforce is saying that I will need some pretty indepth code to get my end result. So I may just give up on this 'extra.' – Liz Jun 19 '14 at 10:36

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.