Calculated fields

Calculated fields

by Mark Butler -
Number of replies: 31
Has anyone found a way to have field that is based on a calculation using data from a previous field.

Example:

Raw data entered by user for Dissolved Oxygen Concentration is 4.

% Oxygen Saturation is calculated by plugging that number into a formula (lets say it is Dissolved Oxygen Concentration X 25=% Oxygen Saturation).

Can I have the list view or single view display the raw data and also display the % Oxygen Saturation (calculated using the formula and the value for Dissolved Oxygen Concentration)?
Average of ratings: -
In reply to Mark Butler

Re: Calculated fields

by Itamar Tzadok -
Sure. If you use a table to display the entries in the list view you can use scripting to traverse the table rows, and for each row calculate the value based on the raw data and add it to the designated cell.

So suppose the table id is 'itemList', the raw value is in cell 3 and the calculated value should be in cell 4. The script may look something like this:

  • var myList=document.getElementById('itemList');
  • var myRows=myList.firstChild.rows;
  • for (var j=1;j<myRows.length;j++){
    • var myCells=myRows[j].cells;
    • var rawVal=myCells[3].innerHTML;
    • var calcVal=rawVal*25;
    • myCells[4].innerHTML=calcVal;
  • }

smile
Average of ratings: Useful (2)
In reply to Itamar Tzadok

Re: Calculated fields

by Mark Butler -
I apologize in advance as I am new to this but the only code that references the table is pasted below. I see no reference to the table id.

<td valign="top" align="right" style="border-style: none; border-width: 4px; background-image: none; text-align: left; vertical-align: top;" rowspan="1" colspan="4">
<table width="100%" border="1" align="texttop"><tbody>
<tr>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top"><br />
</td>
</tr>
<tr>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top">25<br />
</td>
<td width="25%" valign="top"><br />
</td>
</tr>
<tr>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top"><br />
</td>
</tr>
<tr>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top"><br />
</td>
<td width="25%" valign="top"><br />
</td>
</tr></tbody>
</table><br />


How do I reference and individual cell?
In reply to Mark Butler

Re: Calculated fields

by Itamar Tzadok -
<td id="mystemcell" width="25%" valign="top">

But consider that if you reference the table

<table id="mydinnertable" width="100%" border="1" align="texttop">

you can access any of the cells by the rows and cells properties of the table element (see above).

smile
In reply to Itamar Tzadok

Calculated fields - saving a calculated result?

by Petteri Pyrrö -

Hi,

I have exercized a little with some simple JavaScript calculations in Database activity Module, such as simple sums in a list view. It works great! But now I'm facing a problem: Is there a way to save a JavaScript-calculated result to a selected database field?

Example: I have a form to calculate BMI (Body Mass Index). The input is person's height (in metric, cm) and weight (in metric, kg). The function is BMI=weight[kg]/(height[m])^2. Let's assume the name of the JavaScipt function is "BodyMassIndex()".

I already accomplished to make a simple script showing the result, but how do I save the result to the database? Logically, BodyMassIndex=document.write(BodyMassIndex()?


In reply to Petteri Pyrrö

Re: Calculated fields - saving a calculated result?

by Itamar Tzadok -
You should have a designated field which you can update in the entry form. Notice that in the 'available tags' list in the add entry template you have a list of field ids which you can use for accessing the field and setting there the value.

Suppose the designated field is a number field called Bmi.
In the 'available tags' list you should see Bmi id - ||Bmi#id||
In the entry template you can add a button and set its onclick event to something like "setBmi();"
Then if you define the setBmi function in the add entry template it can be something like:

function setBmi(){
document.getElementById("||Bmi#id||").value=BodyMassIndex();
}

Of course the user will have to click the button to update the field. If you want it to be calculated and updated automatically you will have to add an event listener to the field and that is a bit more complicated especially if you need to support different browsers.

Hope this helps. smile
Average of ratings: Useful (1)
In reply to Itamar Tzadok

Vast: Re: Calculated fields - saving a calculated result?

by Petteri Pyrrö -
Thanks! Haven't got it to work yet, but I'll keep hacking Hymy ...I've been trying to make it to show the result to the user at the same time; I've probably mixed something up with the id's...
In reply to Itamar Tzadok

Re: Calculated fields - saving a calculated result?

by Tieku Bortei-Doku -

Itamar,

In the entry template you can add a button and set its onclick event to something like "setBmi();"


How exactly do you do that. What do you put in place of the regular fieldname in the entry template?

Where exactly do you place

function setBmi(){
document.getElementById("||Bmi#id||").value=BodyMassIndex();
}

Thanks


In reply to Tieku Bortei-Doku

Re: Calculated fields - saving a calculated result?

by Itamar Tzadok -
You add at the bottom something like:

<script type="text/javascript">
function setBmi(){
document.getElementById("||Bmi#id||").value=BodyMassIndex();
}
</script>

The idea is that when the template is parsed all identified bracketed names are replaced with their assigned values and so the
||Bmi#id|| will be replaced with the field id (e.g. field_243).

You can also put the function definition of BodyMassIndex() inside this script or put it in the javascript template.

Then you simply add a button anywhere in the form:

<input type="button" Xonclick="
setBmi();" />

Needless to say (but said anyway wink) all that should be done in html mode.

smile
In reply to Itamar Tzadok

Re: Calculated fields - saving a calculated result?

by Peter Evans -

Does anyone have an example database where a field is calculated using Javascript based on previous values in that recond. A functioning database makes is a lot easier to undertand how it all works.

Thansk in advance for any assistance,

Peter

In reply to Peter Evans

Re: Calculated fields - saving a calculated result?

by Itamar Tzadok -

Shouldn't be too difficult to construct an example. What sort of scenario do you have in mind? (e.g. update upon opening, update upon changing another field, button click, etc.) smile

In reply to Itamar Tzadok

Re: Calculated fields - saving a calculated result?

by Peter Evans -

Thanks for assisting.  An example might be people enter height and weight and the database displays a the BMI in a third field. I imagine it is easiest to display this when the page is displayed (also means that the value is always updated).

Would be good if it was display in list mode for all records but this would mean that JS would have to cycle through all rows when someone clicked a button or on display.

Example drawn from the above but I am just unsure of how to pull it all together. If you can give me an example of a page that does it I can generate the Moodle templates from that.  Thanks in advance for your assistance.

The input is person's height (in metric, cm) and weight (in metric, kg). The function is BMI=weight[kg]/(height[m])^2. Let's assume the name of the JavaScipt function is "BodyMassIndex()".

<script type="text/javascript">
function setBmi(){
document.getElementById("||Bmi#id||").value=BodyMassIndex();
}
</script>

In reply to Peter Evans

Re: Calculated fields - saving a calculated result?

by Itamar Tzadok -

One possible implementation is by assigning the bmi function to the onkeypress event of the weight and height fields. Then Entering a weight and height in the entry form will automatically update the BMI (the BMI will be updated only when height is greater than 0).

Works in FF and reasonably well in IE8.

Preset attached. smile

Average of ratings: Useful (1)
In reply to Itamar Tzadok

Re: Database preset showing use of Javascript to automagically calculate field contents

by Peter Evans -

Itamar,

Excellent ... thank you very much for "putting all the dots close enough together" for me to easily follow the example. I'll demonstrate this to in a Moodle training session tomorrow (with due credit given to you).  Being able to do calculations as the data is input greatly increases the power of the database activity.

For those who do not download the preset the database contains 3 fields

  • Weight
  • Height
  • BMI

and the Add template contains this HTML

<table cellpadding="5">
<tbody>
<tr>
<td align="right" valign="top">Weight:</td>
<td>Weight</td>
</tr>
<tr>
<td align="right" valign="top">Height:</td>
<td>Height</td>
</tr>
<tr>
<td align="right" valign="top">BMI:</td>
<td>BMI</td>
</tr>
</tbody>
</table>
<script type="text/javascript">// <![CDATA[
document.getElementById('Weight#id').Xonkeypress=function(){setBmi();};
document.getElementById('Height#id').Xonkeypress=function(){setBmi();};
function setBmi(){
var weight=document.getElementById('Weight#id').value;
var height=document.getElementById('Height#id').value;
if (Number(height)>0){
document.getElementById('BMI#id').value=Number(weight)/Math.pow(Number(height),2);
}
}
// ]]></script>

Thanks again,

Peter Evans

In reply to Peter Evans

Re: exxample database showing use of Javascript to automagically calculate field contents

by Peter Evans -
In reply to Peter Evans

Re: exxample database showing use of Javascript to automagically calculate field contents

by Jamie Tinley -

I'm crying uncle. After 2 weeks I can't seem to figure this out myself.  I'm on moodle 2.4 on a lamp system on server 2008.  I just want to calulate in one column using another. I tried the two examples I found on moodle without luck.  They were zip files that did not even load until I changed them to .mbz and then they failed with these errors:

Debug info: 
Error code: cannot_precheck_wrong_status 
$a contents: 200

Stack trace:
  • line 336 of \backup\controller\restore_controller.class.php: restore_controller_exception thrown
  • line 403 of \mod\dataform\preset\preset_manager.php: call to restore_controller->execute_precheck()
  • line 249 of \mod\dataform\preset\preset_manager.php: call to dataform_preset_manager->apply_preset()
  • line 54 of \mod\dataform\preset\index.php: call to dataform_preset_manager->process_presets()

Here are the one's I tried:

BMI_-_JS_to_calculate_field_and_lists_horizontally

Calculated_field-preset-20110131_0107

Then I downloaded my own example by making a preset of the dataform. Upon opening it and comparing to those above they have very different contents. 

2nd I tried for another week learning Java and programming it in.  I found 19 websites with examples and a bunch frrom Itamar - pasted them all in with many variations without joy.

I assume the javascript or html goes into the repeated entry section by going to manage tab then click view then in my case edit the tabular view.  I changed them to Plain text view in the drop down as well as on my profile because it kept deleting my code.  I got some java scripts to work but I can't seem to get any values corresponding to the items in my table. I set up a table with the same values as in the BMI example but in my dropdown I don't see choices like Weight#id  instead I see weight  so where do I find the correct id name so I can use it?

I tried various scripts from these links without success so I'm missing the concept of identifying the objects and cells in my code.  For example why are these two suggestions so different:

%%F1:=||Lecture 1:value||+||Lecture 2:value||+||Lecture 3:value||+||Lecture 4:value||%%

and a snippet of this code both used as solutions for dataforms

<script type="text/javascript">// <![CDATA[
document.getElementById('Weight#id').Xonkeypress=function(){setBmi();};
document.getElementById('Height#id').Xonkeypress=function(){setBmi();};
function setBmi(){
var weight=document.getElementById('Weight#id').value;
var height=document.getElementById('Height#id').value;

Why does one use ( ) and # signs before the value and the other uses [] and .value is
inside: ex ("Weighted#id).value vs [Lecture 1 .value]
I figured out that F1 meant all the data cells for col F and F2 is for the header but I
tried using C1 for my 3rd column for BMI and I could not get anything to show up.

I realize I am so behind the curve that I'm a project needing much more than just
tweaking but if I could only get an example to load I could figure it out easier. I did
the same thing 10 years ago with VBA and now I can use it to solve a lot of things.
I'm hoping this does not take me 10 years though.

Thanks in advance :) JT
In reply to Jamie Tinley

Re: exxample database showing use of Javascript to automagically calculate field contents

by Itamar Tzadok -

Jamie, I think you've tried to upload a Database preset into a Dataform and that won't work as Dataform presets are completely different from the Database's.

In the Dataform you can use formulas to manipulate numbers display including aggregation of column (displayed) values.

See illustration below for aggregating.

The aggregation is a formula that aggregates formulas.

There are a few open issues with this feature especially in editing mode and I'm hoping address them soon. smile

Template

 

 

View

Average of ratings: Useful (1)
In reply to Itamar Tzadok

Re: exxample database showing use of Javascript to automagically calculate field contents

by Jamie Tinley -

Awesome! it works! Thank you so much Itamar!  I did not expect a reply so fast and I figured It would take another 2 weeks to make it work. 

Thank you thank you! 

Is there a list of functions I can perform on it? Thanks again!

Jamie

In reply to Jamie Tinley

Re: exxample database showing use of Javascript to automagically calculate field contents

by Itamar Tzadok -

The Dataform uses for formulas the same moodle lib that is used by the gradebook formulas and you can find a list of functions (in addition to the standard arithmetic operators) at http://docs.moodle.org/23/en/Grade_calculations.

At some point I will add logical operators.

A few tips for Dataform formulas:

- The F index of an aggregation should be lower than the F index of the aggregated (e.g. F1 can aggregate F3 but not vice versa).

- The aggregation works on subsequent formulas where ever they are and is neither limited to a particular column nor to a particular sub formula. So an aggregation such as %%F:=SUM(_F1_,AVERAGE(_F2_))%% should also work.

- The '!' prefix of the field name inside the formula disables editing mode for the field tag in the formula.

- You can aggregate in the table row level by using the entry id as the F index of the aggregated formulas (which will make the F indices unique per row). See illustration.

 

hth smile

 

 

 

Average of ratings: Useful (1)
In reply to Itamar Tzadok

Calculate age field from system date and birthday date fields

by David Le Blanc -

Does anyone know how to get the current month and day from moodle and use it to calculate/display the user's age? The user will have entered their birthday in a date field. 

For example:
Current system date = 2013/05/15 - User entered birthday =1995/04/10
= 2013 - 1995/05 - 4/15 - 10
= 0018/01/05

  Calculated Age = 18

I am unsure how to access the current year/month fields from both the system and from the manually entered birthday for the current user's record. mixed

In reply to Itamar Tzadok

Re: exxample database showing use of Javascript to automagically calculate field contents

by Noah Freedman -

Itamar

Does the current version of Dataform (2012100500) support these formulae?  I have tried, but all I get in the browse view are the formulae themselves, not the calculated results.

Thanks

Attachment Screen Shot 2013-06-24 at 14.00.14.JPG
In reply to Noah Freedman

Re: exxample database showing use of Javascript to automagically calculate field contents

by Stephanie Gerald -

Hello. Has anyone tried this recently on Moodle 2.8? I can't get this to work, like in Noah's previous post. 

Is there a trick to get this to work that we don't know about? I've used the same as Noah above and it only displays the formulae, not the calculated results.

Any help would be greatly appreciated.

In reply to Stephanie Gerald

Re: exxample database showing use of Javascript to automagically calculate field contents

by William Lu -
Picture of Particularly helpful Moodlers

The Standard Database module can do the calculation job with some JavaScript.

1,2

3,4

Please feel free to use the attached preset as your start point. Some lines are comment out. It was prepared for calculating more fields.

Hope this help and let me know if you need me to edit it for you. (btw: don't forget vote as useful smile)


Average of ratings: Useful (2)
In reply to Stephanie Gerald

Re: exxample database showing use of Javascript to automagically calculate field contents

by Itamar Tzadok -

It works on Moodle 2.8. Moreover you can simplify your view templates by entering the formulas in the template of a text field and then add to the view template the field template pattern. If you need further assistance with the Dataform, please post your question in the Dataform forum at https://moodle.org/mod/forum/view.php?id=8192. hth smile

In reply to Itamar Tzadok

Re: Calculated fields - saving a calculated result?

by Sarah Ashley -

Hello Itamar,

This is fantastic, thanks so much for explaining! I was able to use the concept to calculate and save the difference between two numbers into a "Balance" field on the Add Entry template.

But I am stumped on calculating the totals of two columns on the List template.

Screenshot of the database list view is attached. And below is the code I have so far for the last row of the table. (in the Footer portion of the List template)

<tr>
<td></td>
<td align="right"><strong>TOTALS >></strong></td>
<td id="totalP"></td>
<td id="totalC"></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<script Xlanguage="javascript" type="text/javascript">
var pledgeList=document.getElementById('pledgeData');
var theRows=pledgeList.firstChild.rows;
var countP=0;
var countC=0;
for (var j=2; j<theRows.length; j++) { j=2 because data starts in row 2 ? thoughtful
var theCells = theRows[j].cells;
countP+=theCells[3].innerHTML;
countC+=theCells[4].innerHTML;
}
document.getElementById('totalP').value=countP;
document.getElementById('totalC').value=countC;
</script>

I am not sure how to make the value of countP and countC show up in the HTML table. I do have two fields called TotalPledges and TotalCollected which I thought I could use to display the result, but the cells show the field names TotalPledges and TotalCollected instead of the figures. I surmised that the fields only "work" in the Repeated Region of the list view. (Please correct me if I am wrong).

Thanks for any light you can shed on where I am going wrong.

Best regards,
Sarah.

Attachment ScriptingTotalsRow.jpg
In reply to Sarah Ashley

Re: Calculated fields - saving a calculated result?

by Itamar Tzadok -

Should be exactly the same method you use to extract a value from a table cell but a "get" rather than "set".

The "get" is something like:

somevar = somecell.innerHTML;

So the "set" should be:

somecell.innerHTML = somevar;

In your case you have

<td id="totalP"></td>
<td id="totalC"></td>

So the last two lines of your script should be:

document.getElementById('totalP').innerHTML=countP;
document.getElementById('totalC').innerHTML=countC;

 

One other suggestion. Since you intend the countP and countC as numbers but you extract the values from innerHTML which is a string and at that html, you may want to explicitly convert the innerHTML to Number just to be on the safe side. Something like:

countP+=Number(theCells[3].innerHTML);

 

hth smile

Average of ratings: Useful (1)
In reply to Itamar Tzadok

Re: Calculated fields - saving a calculated result?

by Sarah Ashley -

Perfect! Just the direction I needed!

I didn't realize you could add .innerHTML to the document.getElementById statement.

Thanks Itamar!

My final database looks like the image attached, and I updated the code for the last row to the following:

<tr class="totalrow**">
<td></td>
<td align="right"><strong>TOTALS >></strong></td>
<td align="right" id="totalP"></td>
<td align="right" id="totalC"></td>
<td align="right" id="totalB"></td>
<td></td>
</tr>
</tbody>
</table>
<script language="javascript" type="text/javascript">
var pledgeList=document.getElementById('pledgeData');
var theRows=pledgeList.firstChild.rows;
var countP=0;
var countC=0;
var countB=0;
for (var j=1; j<theRows.length; j++) { start j from 1 not 2, as it automatically skips the heading row
var theCells = theRows[j].cells;
countP+=Number(theCells[2].innerHTML); also note that column 1 is really [0]
countC+=Number(theCells[3].innerHTML);
countB+=Number(theCells[4].innerHTML);
}
document.getElementById('totalP').innerHTML=countP;
document.getElementById('totalC').innerHTML=countC;
document.getElementById('totalB').innerHTML=countB;
</script>

**the row class is just for css, not the script

Thanks again!
Yes
Sarah

Attachment TotalsRowInListView.jpg
In reply to Itamar Tzadok

Re: Calculated fields - saving a calculated result?

by Tieku Bortei-Doku -

This preset works OK. But, what do I need to change - instead of the user typing in the numbers for weight and height, they are selecting a number from a drop-down menu field. Thanks

In reply to Tieku Bortei-Doku

Re: Calculated fields - saving a calculated result?

by Tieku Bortei-Doku -

Another question - I am using the preset above Itamar made available. I have made a simple change to the calculation line to test addition.

document.getElementById('BMI#id').value=Number(w)+Number(h );

In Firefox and Opera the result of 10 + 10 = 20
but in IE and Safari the result of 10 + 10 = 11?

What would explain this behavior?

In reply to Mark Butler

Re: Calculated fields

by William Lu -
Picture of Particularly helpful Moodlers

Please download my iMoot15 presentation's files about how to create a calculable database:

https://moodle.net/mod/data/view.php?d=1&rid=135

Average of ratings: Useful (5)
In reply to William Lu

Re: Calculated fields

by Stuart Mealor -

I very much enjoyed this presentation at the iMoot.

I strongly recommend anyone interested in advanced use of the Database module, and using calculations, to take a look at William's work smile

Average of ratings: Useful (1)
In reply to Stuart Mealor

Re: Calculated fields

by Sarah Ashley -

I agree with Stuart! Thanks for a great presentation at iMoot 2015, William!

Yes