# Cannot calculate with Dynamic variables in a grid

This is a prototype of a grading scheme. In reality it is bigger. The 10 pts in initPtsPartA comes from the school.

The output cell should be deployed as a CDF file for the teacher. The teacher enters the points of the students and get a final mark.

I have two questions.

1) How can I limit the InputField to allow for integer numbers between 0 and 10? If I enter anything else, say a negative number or a symbol, it should be cleared automatically.

2) In the Code Snippet section "Why don't the calculations work?" you see expressions with Dynamic variables which I need to work with. What is wrong? What is the solution?

DynamicModule[{
mark4 = 1/3, mark3 = 0.51, mark2 = 0.68, mark1 = 0.80,
initPtsPartA = {{10, 8, 10, 6}, {10, 5, 10, 5}, {10, 7, 10, 1}},
initPtsStudent, initPtsSchool, initPtsPartSum, numTable,
SchoolAPts, StudentAPts, StudentMinAchieved
},

numTable[x_, y_ /; OddQ[y]] := initPtsPartA[[x, y]];
numTable[x_, y_ /; EvenQ[y]] := InputField[Dynamic@initPtsPartA[[x, y]],
Number, ContinuousAction -> True, FieldSize -> 1];

initPtsPartSum[x_, y_, col_] := Dynamic@Total[initPtsPartA[[x ;; y, col]]];

SchoolAPts = (Total[initPtsPartA[[1 ;; 3, #]]] &) /@ {1, 3};
StudentAPts = (initPtsPartSum[1, 3, #] &) /@ {2, 4};

(* CODE SNIPPET, part of a longer program with Graphics involved. *)

Column[{Grid[
Append[ Array[numTable, {3, 4}], (initPtsPartSum[1, 3, #] &) /@
Range[4]]],

{"Just Testing Values:", initPtsPartSum[1, 3, 1],
initPtsPartSum[1, 3, 2], initPtsPartSum[1, 3, 3],
initPtsPartSum[1, 3, 4], "Student Pts only:", StudentAPts},

{"Why don't the calculations work?",
Dynamic[5*initPtsPartSum[1, 3, 2] + 10],
Dynamic[initPtsPartSum[1, 3, 4] > 30],
Dynamic[ Total[(initPtsPartSum[1, 3, #] &) /@ Range[4]]  ],
Dynamic[(Total@StudentAPts)]/(Total@SchoolAPts)},

{"Why don't the calculations work?",
StudentMinAchieved =
Dynamic[(StudentAPts[[1]]/SchoolAPts[[1]] >
mark4) && (StudentAPts[[2]]/SchoolAPts[[2]] > mark4)]}
}]
]

-

1. Use something like

SetAttributes[restrictedInputField, HoldFirst];
restrictedInputField[expr_] :=
InputField[Dynamic[expr, (If[0 <= # < 10, expr = #] &)], Number, FieldSize -> 1];


and do not use ContinuousAction -> True (if there is a way to make it work with it, I don't know it). Your code will then look like:

numTable[x_, y_ /; EvenQ[y]] :=
restrictedInputField[initPtsPartA[[x, y]]];


and you can make restrictedInputField also local to your DynamicModule. The price to pay is that the input gets updated only after either Enter is perssed (after the number is typed in), or the focus leaves the input field. To my mind, this is acceptable, but of course you may have different opinion.

2. Do not use Dynamic in

initPtsPartSum[x_, y_, col_] := Dynamic@Total[initPtsPartA[[x ;; y, col]]];


initPtsPartSum[x_, y_, col_] := Total[initPtsPartA[[x ;; y, col]]];

By wrapping Dynamic around it, you prevent any arithmetic with it, since the Dynamic wrapper stays wrapped around your expression in all arithmetic etc operations you perform later.
What is the issue with ContinuousAction->True Leonid? – Rojo Nov 24 '12 at 20:28
Oh, well, you can't delete because when you delete the value it becomes Null (which is allowed even when you only allow Number) and Null isn't 0 <= # < 10 &. But allowing for Null fixes it in my machine. Also, you could select the digit before typing the new one so you don't go through Null – Rojo Nov 24 '12 at 21:48