2
$\begingroup$

Starting with a fresh kernel, I evaluate the following:

Questions = {
    (* Statement, Answer, Incorrect Answer *)
    {"What is the capital of Switzerland?", "Bern", {"Vaduz", "Berlin", "Vienna"}},
    {"Who is the king of the jungle?", "Lion", {"Giraffe", "Mouse", "Monkey"}},
    {"2+2?" , "4", {"15", "13", "1e15"}}
} ;
Dynamic@Column@Questions

SetAttributes[DynamicInputField, {HoldFirst, Listable}];
DynamicInputField[var_, OptionsPattern[ContentType -> Expression]] := 
  InputField[Dynamic[var], OptionValue[ContentType], 
   ContinuousAction -> True, ImageSize -> Full];

Dynamic@Grid[{
   {"Statement", DynamicInputField[Questions[[1, 1]], ContentType -> String]},
   {"Answer", DynamicInputField[Questions[[1, 2]], ContentType -> String]},
   {Column[{"Incorrect Answers"}, BaselinePosition -> Top], 
    Column[DynamicInputField[#, ContentType -> String] & /@ Questions[[1, 3]],
        BaselinePosition -> Top]
   }
}, Alignment -> Left]

Statement

I must say that I took me a while to find out that I needed to set HoldFirst as an attribute for my function to work at least with the first two input fields. Nevertheless, the function does not work by mapping it into a list, i.e., the three last input fields send a error, the same one I had before I set HoldFirst as an attribute:

Set::setraw : Cannot assign to raw object Vaduz.>>

What am I doing wrong? I also tried the following:

Column[DynamicInputField[Questions[[1, 3]], ContentType -> String], 
    BaselinePosition -> Top]

Attempt1

Column[Table[
    DynamicInputField[Questions[[1, 3, n]], ContentType -> String], 
    {n, 3}], BaselinePosition -> Top]

Attempt2

Giving the errors:

Part::pkspec1 : The expression n cannot be used as a part specification.>>

even when I put the Table inside a With[[n=n],...].

Moreover, why is not the same result in my two attempts of "solving" even though the function was set to be listable?

$\endgroup$

1 Answer 1

4
$\begingroup$

Fundamental problem

Pardon me if I miss some points of your question as I didn't attempt to understand what your code is intended to do, because I think I understand what the problem is from the title alone. Please consider:

SetAttributes[f, {HoldFirst, Listable}];

f[x_] := foo[x]

f[{1, 2, 3}]
{foo[1], foo[2], foo[3]}
bar = {1, 2, 3};
f[bar]
foo[{1, 2, 3}]

Listable can only work across lists that it can "see" and HoldFirst prevents bar from evaluating to an explicit list.


Analysis of attempts

Your first attempt: Column[DynamicInputField[ . . . fails because the expression returned by DynamicInputField is not a List but an InputField, therefore Column has nothing to format.

Your second attempt is almost correct except that n is not evaluated (because of HoldFirst).
It will work if you put the With inside the Table:

Column[Table[
  With[{n = n}, DynamicInputField[Questions[[1, 3, n]], ContentType -> String]], {n, 3}], 
 BaselinePosition -> Top]

It would be simpler however to use Array. (See below.)


Proposed solution

I believe this will work as you require.

ClearAll[DynamicInputField]
SetAttributes[DynamicInputField, {HoldFirst, Listable}];

DynamicInputField[var_, opts___] /; ListQ[var] := 
  Column @ Array[DynamicInputField[var[[#]], opts] &, Length @ var]

DynamicInputField[var_, OptionsPattern[ContentType -> Expression]] := 
  InputField[Dynamic[var], OptionValue[ContentType], ContinuousAction -> True, 
   ImageSize -> Full];

Test:

DynamicInputField[Questions[[1, 3]], ContentType -> String]

enter image description here

Also:

DynamicInputField[Questions[[1]], ContentType -> String]

enter image description here

$\endgroup$
9
  • $\begingroup$ Specifically, I would like that DynamicInputFiled worked by giving it either a variable like Question[[1,1]] or by giving it a list such as Question[[1,3]] by giving me a FieldInput as defined or a list of those. I didn't know what you mentioned above about how Listable "sees". That might be the reason it doesn't work. $\endgroup$ Jul 29, 2014 at 12:00
  • $\begingroup$ @Carlos Okay, I actually read your code this time. I believe that this is indeed the problem, but I don't see a simple solution because of the way this is written. Let me think about this. $\endgroup$
    – Mr.Wizard
    Jul 29, 2014 at 12:08
  • $\begingroup$ Thanks. And by giving it a second though, I don't actually need that the function can handle either an expression or a list - by being able to map it to a list should do (I tried that but didn't work either). $\endgroup$ Jul 29, 2014 at 12:17
  • $\begingroup$ As suggested by @Mr.Wizard, removing HoldFirst and then just using Column[DynamicInputField[Questions[[1, 3]], ContentType -> String], BaselinePosition -> Top] works for me. $\endgroup$
    – carlosayam
    Jul 29, 2014 at 12:25
  • $\begingroup$ @Carlos Please see my extended answer. $\endgroup$
    – Mr.Wizard
    Jul 29, 2014 at 12:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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