Nested Controls

Mar 25, 2010 at 10:27 AM

Hi. I've implemented this solution and it works a treat. Great job. Now trying to work out how to make addition controls appear on the form when a question (say a yes/no radio button) is answered as 'yes'. Assume that all the controls need to initially be loaded but some set as not visible until some jquery tells it to. Also take it that the field types will need a new parent property and probably a visible property too?

Look forward to your thoughts.

Mar 30, 2010 at 2:16 AM

Thanks for the kind words. I will give this some thought and try some things out. Since we can set the values of any attributes of the generated html elements, it shouldn't be too difficult to create some javascript that is generic enough to hide/show other fields based on input.

When I have something, I'll post or send to you.

 

Mar 30, 2010 at 4:12 AM

I whipped something up, lickity split. Is this what you are talking about?

Check this out: http://ronnieo.net/code/MvcDynamicForms_hiding_fields.zip (temporary link)

Mar 30, 2010 at 9:42 AM

That was quick. Thanks, have had a look and it works but is probably not flexible enough when you have lots of fields and different ones triggering different things. I've just managed to implement it by adding a couple of InputHtmlAttributes for ID and ParentID and then some JQuery which seems to work quite well. Let me know if you are interested in the code.

Now, I think someone raised this in another post, need to work on a better layout (preferably a table) so that labels are on the left and controls on the right. Any thoughts on that?

Mar 30, 2010 at 11:55 AM

Yes, please send the code.

I am working to release this with a layout templating feature to accomodate the table layout.

Mar 30, 2010 at 12:04 PM
OK. Ignoring the actual IDs 120 and 121 as these will all be pulled from a database, in the form provider for a Yes/No radiobutton: question.InputHtmlAttributes.Add("Value","xxx"); // to prepopulate data question.InputHtmlAttributes.Add("ProductAttributeID", "121"); question.InputHtmlAttributes.Add("ParentID", "120"); Then in the aspx: $('div.MvcFieldWrapper :input').focus(function() { var ProductAttributeID = $(this).attr("ProductAttributeID") * 1; var Value = $(this).val(); var AllProductAttributesForParentID = "(this)[ProductAttributeID*=" + $(this).attr("ParentID") + "]"; if (Value == "No") { $(AllProductAttributesForParentID).closest('div.MvcFieldWrapper :input')[1].checked = true; $(AllProductAttributesForParentID).closest('div.MvcFieldWrapper').fadeOut(); } else if (Value == "Yes") { $(AllProductAttributesForParentID).closest('div.MvcFieldWrapper').slideDown('slow'); $(AllProductAttributesForParentID).closest('div.MvcFieldWrapper :input').removeAttr('checked').removeAttr('selected'); } }); Can probably be coded better but just wanted to see if I could get it working. Look forward to the layout ...
Mar 30, 2010 at 1:28 PM

That works, too. I wouldn't create my own HTML attributes, though. Something just doesn't feel right about that and it doesn't validate. I like using the class attribute for these sort of things. You could set parent ID there. Many jQuery plugins work with data set in an html class attribute. But, whatever works for you is great.

Another possibility that I am throwing around is adding a dictionary to each field that can hold arbitrary data. Then we could render a hidden input element next to the field input element that has a JSON string as it's value. That would make getting to the data and using it pretty easy, I think.

Mar 31, 2010 at 4:15 PM
I think you're right. So I should create ProductAttributeID and ParentID class attributes in the InputField abstract class and work from there correct?
Apr 1, 2010 at 4:18 PM

Standby. I am working on an update that will show what I mean.

Apr 1, 2010 at 4:23 PM
Looking forward to it. The tricky bit is getting JQuery to handle it before the form is submitted as otherwise you wouldn't realise you had more questions to answer until you've submitted once. One more thing, how do I go about pre-populating a radio button as either 'Yes' or 'No'?
Apr 1, 2010 at 4:24 PM

This is getting good guys!

Apr 1, 2010 at 4:36 PM

Setting the default selected choice is easy. The field choices are represented as a Dictionary<string,bool>.

So, here's how I would make a radio list and preselect one of the options:

            var gender = new RadioList
            {
                DisplayOrder = 30,
                Title = "Gender",
                Prompt = "Select your gender:",
                Required = true,
                Orientation = Orientation.Vertical
            };
            gender.AddChoices("Male,Female", ",");
            gender.Choices["Female"] = true; // select female by default

 

Apr 1, 2010 at 4:44 PM
Nice one. Have being stuck on that for an hour! Have managed to get textboxes prepopulating using question.InputHtmlAttributes.Add("Value", "xxx"); though I know you won't be happy that I used InputHtmlAttribute.
Apr 1, 2010 at 4:54 PM

Why wouldn't I be happy about that? That's exactly why I exposed that collection!

Apr 1, 2010 at 7:24 PM

BTW, check the home page here to see what I am planning to release soon. 

Apr 1, 2010 at 7:30 PM
Edited Apr 1, 2010 at 7:31 PM

Ronnie,

New features looks awesome!  Only other thing I can think of that maybe only is a concern to my scenario is multiple forms on the same view.

In my application I have a need to allow the user to create tabs and then on each tab, they can add fields using jquery tabs.

 

Apr 3, 2010 at 5:59 AM

I've been working on the new features. I think I have the templating feature complete. You can check out my work if you'd like: http://drop.io/mvcdynforms

Of course, that's not the official release. The release will have more features and a much better demo application bundled with it.

Let me know what you think of the templating. There is a table form in the demo at that link. Look at the TestController.

Apr 5, 2010 at 4:31 PM

I'm checking it out now...

Apr 7, 2010 at 4:05 PM
Look forward to it. When were you thinking of releasing it? Have just been trying to get dropdownlists working slightly different to yours where the value is different to the option displayed on screen. For example, the html that is generated at the moment is <option value="Alabama">Alabama</option> <option value="Alaska">Alaska</option> <option value="Arizona">Arizona</option> but ideally you would want <option value="1">Alabama</option> <option value="2">Alaska</option> <option value="3">Arizona</option> where the values correspond to a database ID. I can get it working so the initial display matches the above but hit problems when you select one, submit and it reloads. It adds an extra option value. Have you looked into this?
Apr 7, 2010 at 5:30 PM

I will release it after I find the time to finish the new features. I will take this into consideration also.

Apr 9, 2010 at 5:17 PM


@Shamen10: About having choices with display text differing from the underlying value: I have implemented this by changing the Choices datatype from Dictionary<string,bool> to List<ListItem>. The ListItem object is very similar to the ListItem object that's been used in Asp.Net for centuries. It's properties are Text, Value, and Selected. I was going to use the ListItem object that comes with Asp.Net, but it wasn't marked as serializable, so I made my own.

Anyway, you can wait for this in the next release, or download my current code: http://drop.io/baxs5g3

Since I am doing all of the incremental changes, I may start checking in my code into the source code repository here. I have to figure it all out, though. Let me know what you think about the changes.

Apr 9, 2010 at 6:10 PM

I added the code to source control here, so you can view my latest change sets from the source code page. Much nicer than drop.io drops. Drop.io does kick some butts, though.

Apr 11, 2010 at 5:55 PM
Just so you know, when I download the zip from the sourcecode page, I got an error when extracting but worked fine from drop.io. Checking out the new Choices datatype now. Whilst I'm at it, how can I see how the templating works - had a look at /Test/Index but it breaks at line 34 on TestController?
Apr 12, 2010 at 1:44 AM

Hmm. It builds and runs just fine for me. I've started checking in my code here on the site, so forget about the drop.io drops. Go to the source code page and download the latest changeset and let me know how it works.

Apr 12, 2010 at 10:10 AM
I went to source code and downloaded mvcdynamicforms-46823.zip which extracts fine now which his odd. When I run it and try /test/index I get an error on line 34 of TestController - form.Fields.Single(x => x.Key == "description").Template = "

" + PlaceHolders.Literal + "

"; The error is "Sequence contains no matching element"
Apr 12, 2010 at 1:26 PM

Sorry, I had the wrong form provider in that change set. Try change set 46905.

Apr 14, 2010 at 12:24 PM
Ah yes that works now and looks very good. One thing I picked up was that using the templated page, the JQuery isn't there. I put it in as per the demo pages but it still doesn't work. Take it that the formatting has stopped the JQuery from working. Another small thing, from the older stable release. ShowEmptyOption = true and EmptyOption = "Select" can be used to add an element at the top of a dropdown list but how do you make it so that in the html it actually appears as Selected. I tried .Choices["Select"] = true but that just adds an additional 'Select' at the bottom of the dropdownlist.
Apr 14, 2010 at 12:54 PM
Edited Apr 14, 2010 at 12:58 PM

The change sets aren't going to be polished, so don't expect everything to work. It's natural that the javascript stops working. The html has changed, so the jQuery selectors aren't relevant. They should be rewritten to match the DOM or to be more tolerant of changes. I am working on a jQuery plugin that should work in most instances.

Why would you want to use the selected attribute for the first option in a drop down list?  Those 2 properties that you mentioned are evaluated when RenderHtml() is called, it doesn't actually add a choice to the list. Now that I have changed the datatype of the choices, I could just remove those EmptyOption properties and let the developers add a ListItem with an empty value themselves.

What do you think?

 

Apr 14, 2010 at 11:01 PM
Yeah I figured, just letting you know. Have managed to incorporate your changeset into the form I was building after making a few tweaks including getting values into dropdownlists but struggling to pre-populate the choices again. Before the changeset I used question.Choices[] = true; to pre-populate but now I guess I need to use something such as question.Choices.Equals(listItem) but can't quite get it correct. Any tips?
Apr 15, 2010 at 2:34 AM
Edited Apr 15, 2010 at 1:25 PM

 

listField.Choices.Single(x => x.Value == "Some Choice Value").Selected = true;

 

I may create a method to make this more concise. Maybe some thing like:

 

public ListItem GetListItemByValue(string value);

 

 

Apr 15, 2010 at 1:05 PM
Great, all working. Back to the point about removing the EmptyOption properties, I have tried removing them and adding an empty value manually but then how does the validation work?
Apr 15, 2010 at 1:20 PM

The (required) validation works fine for me when I add an empty option manually before adding the rest of the choices, I can even ensure that the empty options has it's selected attribute:

var month = new Select
{
    DisplayOrder = 70,
    ResponseTitle = "Month Born",
    Prompt = "What month were you born in?",
    Required=true
};
month.Choices.Add(new ListItem { Text = "- Select One -", Selected = true });
month.AddChoices("January,February,March,April,May,June,July,August,September,October,November,December");

 

Apr 15, 2010 at 1:21 PM

Oh, by the way, please start a new thread for future unrelated questions. Thanks.

 

Apr 15, 2010 at 4:07 PM
Yeah sure. All works well so I guess you could remove the EmptyOption properties. This is a better implementation.