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.
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).