ASP MVC dynamic fields in editor - asp.net

I have a form which will include some optional questions that need to asked of the user. In my model it may look like:
public Dictionary<String, String> Questions { get; set; }
Where the key is the label and value is the text box. How can I create and populate the controls for this? I am new to ASP MVC, but it makes sense that something like this would be built in.
Is there a built in way to do this, or do I have to implement it myself? It seems like there should be a helper for it, since you don't really want to put this kind of code in the view.
I've tried
Html.EditorFor(model => model.Questions);
But it just spits out "[key, value]" to the view.

There are a couple of ways you could go here.
You could write your own helper quite easily - maybe something like this:
public static string Question(Dictionary question)
{
Html.Label(question.Key);
Html.Textbox(question.Value);
}
Create a custom display template for Dictionary<string, string> (or, rather, wrap the dictionary in a Question type to avoid ambiguity) that outputs what you want.

Why not implement a Question class?
Something like this I had in mind:
public class QuestionControl
{
public int QuestionId{get;set;}
public string Question{get;set;}
public string Answer{get;set;}
public virtual string GetHtml()
{
return string.Format("<label for=\"{0}\">{2}</label><br><input type=\"text\" name=\"{0}\" id=\"{0}\" value=\"{1}\">", QuestionId, Answer, Question);
}
}
Also, this way you can inherit and override GetHtml and have questions with checkboxes, radiobuttons etc.

Related

How can I create more than one Model in a view? Preferably using Partial Views and a dynamic number of models

I have list of "skills" that I want a user to be able to go through, selecting appropriate levels from the list. So Skill looks something like this:
public class Skill
{
public String SkillName { get; set; }
public SkillLevel CurrentSkillLevel { get; set; }
public Boolean IsRequired { get; set; }
public Skill(String Name)
{
this.SkillName = Name;
this.IsRequired = true;
this.CurrentSkillLevel = SkillLevel.None;
}
}
There could be hundreds of skills - and the exact number is unknown at the moment, and certainly it needs to be dynamic, so I don't want to make the user go through the process of clicking on each skill, filling out the form, and submitting each time. I'd like to display all of the skills in the same page (one row each), allow the user to select all the values, then click submit once at the end.
Unfortunately, I've not had any experience with using MVC for anything other than singleton creation. I would normally use a separate ViewModel for several models bundled together, but I don't see how that would work with a dynamic list, and since they are all the same type ("Skill"), I guess the ViewModel would look exactly like a list of the model.
Does anyone have an appropriate solution?
Thanks
Building on DaveA's answer, you can use an editor template for Skill. You will need to add a folder named EditorTemplates to your Views\Controller folder. Now make a partial view in that folder named Skill.cshtml that looks something like this
#model Skill
#Html.TextBoxFor(s => s.SkillName)
#Html.TextBoxFor(s => s.Skills[i].Title)
// etc...
Now in your main view
using (Html.BeginForm("UpdateCart", "Orders"))
{
#Html.TextBoxFor(p=>p.Name)
#Html.TextBoxFor(p=>p.Title)
#Html.EditorFor(p => p.Skills)
}
Razor is smart enough that it will render each skill in Skills using the Skill.cshtml editor template.

ASP.net how to extend a control or collection

I am attempting to extend a List. When using Visual Studio there are the different code hints for all the functions I can use with a List object. How can I extend the functionality of the List to show my new function?
public class ListExtensionHelper<T> : System.Collections.Generic.List<T>
{
public List<T> AwesomeFunction<T>()
{
}
}
For the life of me I could not find anything online on how I would do it for a List
If you are trying to add AwesomeFunction as an extension method to a regular List object, then you need to define an extension method in a static class:
public static class ListExtensions
{
public static List<T> AwesomeFunction<T>(this List<T> list)
{
}
}
Otherwise, the code you have should work; if you instantiate the ListExtensionHelper class, it should have all the functions of List as well as AwesomeFunction.
It sounds like you're looking for extension methods, rather than inheritance.
There are some really good examples here. There's also a really good library of extensions available here.
<soapbox>
One of my personal favorites that I use is this:
public static class StringExtensions
{
public static bool IsNullOrEmpty(this string s)
{
return string.IsNullOrEmpty(s);
}
}
It's ridiculously simple, but a huge pet peeve of mine is having to write:
if (string.IsNullOrEmpty(someVariable))
as opposed to:
if (someVariable.IsNullOrEmpty())
For me it's just a matter of being a natural construct of my native language. The built-in method sounds like:
object verb subject
whereas mine sounds like:
subject verb
It's probably silly, but when I want to act upon a subject it just makes more sense for me to start with the subject :)
</soapbox>

Where to put custom object formatter in ASP.NET MVC application?

I'm teaching myself ASP.NET MVC, and am trying to figure out where best to put a function which takes in an Models.Address instance and returns an IHtmlString instance which reads something like:
Line 1<br />
Line 2<br />
City, State
The string could be used in many places throughout my project, so I don't want to write it in one view and have to keep copy-pasting it or attaching that view: By the same logic attaching it to ViewData seems like a bad idea. However, the HtmlEncode method requires an instance of server, which means I can't add the function to the model class either.
Is there a right place to put this - some sort of shared view? (does this belong in the master?) Or am I going about this all wrong?
My current best idea is to create a ViewModel with the method public IHtmlString FormatAddress(Address address, HttpServerUtility server), but I don't know if that's the ASP.NET MVC way to do it.
As this is presentation UI logic, the best place to put it is in a HtmlHelper class.
public static class HtmlHelper
{
public static HtmlString FormatAddress (this HtmlHelper, Address address)
{
string formattedAddress = // the formatted address...
return HtmlString.Create(formattedAddress);
}
}
then, from any view you simply call:
<%= Html.FormatAddress(address) %>
I usually create something like that as an Extension Method on a HelperExtensions class and then place that class in a Helpers folder at the top level of the site.
public static class HelperExtensions
{
public static Format(this Address address, HttpServerUtility server)
{
// Do the work to format here.
}
}

ASP.NET MVC: How to transfer more than one object to View method?

I finished NerdDinner tutorial and now I'm playing a bit with project.
Index page shows all upcoming dinners:
public ActionResult Index()
{
var dinners = dinnerRepository.FindUpComingDinners().ToList();
return View(dinners);
}
In DinnerRepository class I have method FindAllDinners and I would like to add to above Index method number of all dinners, something like this:
public ActionResult Index()
{
var dinners = dinnerRepository.FindUpComingDinners().ToList();
var numberOfAllDinners = dinnerRepository.FindAllDinners().Count();
return View(dinners, numberOfAllDinners);
}
Of course, this doesn't work. As I'm pretty new to OOP I would need help with this one.
Thanks,
Ile
Create view model:
public class DinnerViewModel
{
public List<Dinner> Dinners { get; set; }
public int NumberOfAllDinners { get; set; }
}
public ActionResult Index()
{
var dinners = dinnerRepository.FindUpComingDinners().ToList();
var numberOfAllDinners = dinnerRepository.FindAllDinners().Count();
return View(new DinnerViewModel { Dinners = dinners, NumberOfAllDinners = numberOfAllDinners } );
}
You need to create a "wrapper" object that contains the objects you wish to pass as public properties of it. For instance, create an object called DinnerViewModel and give it two properties and set these with two properties, one a List called Dinners and one an int called DinnerCount. Then pass the DinnerViewModel to the view and you can then access Model.Dinners and Model.DinnerCount
In your case I would prefer the solution mentioned by LukLed.
In general you could of course also transfer multiple values from your controller to your view using ViewData:
ViewData["dinners"] = dinners;
ViewData["numberOfAllDinners"] = 150;
...
For more information also take a look at this link.
Just simply use dinners.Count property instead.
Remember, you start off using the ViewData inherts in you .aspx filesand returning the same in you return statements. Because of that, I figure that it was an issue with the Inherits attribute on the top of the ASP.NET files. But, if you are getting the error when trying to create or edit a new Dinner when you are on the 'Upcoming Dinners' page (generated from the Details.aspx and the LINQ file that gets all Dinners that are after todays date), go into your 'Controllers' directory, specifically the DinnerController.cs. Then look at the Edit and or Create methods. the answer lies right here. If you put breakpoints on these methods, you should be able to figure it out. If not, continue reading:
Look where it fails, the 'return...' line. Maybe I am the only person who forgot to change this, but my error is the same as people are getting in this page and this os how I fixed it.....the 'return(dinner)' line, in Create and Edit (and any others that you are having issues with), they are using the NerDinner.Model.Dinner / ViewData method. However, if you change it to the ViewModel return method instead, it should fix it, For example: 'return(new DinnerFormViewModel(dinner));', it should work for you. I hope this helps, as it was what my issue was. Just a simple overlook.

How can I emulate ErrorProvider in .NET Compact Framework?

Since there is no ErrorProvider class in .NETCF, how can I implement similar functionality (not necessarily exactly like ErrorProvider)?
I am using all the regular databinding constructs to bind controls to a datatable, using the DataRow.RowError property and DataRow.SetColumnError method, but I can't find events on any of DataTable, BindingManagerBase, etc. that I can hook into to receive any sort of notification.
Am I stuck calling a method to manually iterate through all the controls on my form and change some look/feel of the bound control?
Thanks,
MrB
The ErrorProvider class seems pretty basic - actually, a little too basic. If you have Red Gate Reflector, I would recommend disassembling the class and looking at it. Otherwise, create a Dictionary<Control, String>.
Here is a quick idea on creating your own provider:
Dictionary<Control, String> ErrorSet = new Dictionary<Control, String>();
public void SetError(Control control, String message)
{
// code for adding error information
ErrorSet.Add(control, message);
}
public String GetError(Control control)
{
// code for retrieving error information
return ErrorSet[control];
}
public String Clear()
{
// code for clearing all errors
}
I don't have R-G reflector here or I would provide more sample methods. But this ought to provide some sort of sample to work from.

Resources