Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
All my controllers in my project inherit from a base controller, which has a property with my Entity Model.
Let say I have a view that shows cities in the world, and it has an option to filter by country. The country filter is a dropdown list of countries from the database. The Html helper for the dropdown list requests a IEnumerable<SelectItem>.
Now with that info, is it ok if I create a HtmlHelper that looks like this:
public static IEnumerable<SelectListItem> GetCountries(HtmlHelper htmlHelper)
{
return (from c in ((BaseController) htmlHelper.ViewContext.Controller).Entities.Countries
orderby c.Name
select new SelectListItem() {Text = c.Name, Value = c.ID});
}
The question is not if I it is possible, but if it is ok according to the MVC way of doing things. (Or should I put the collection of countries in the ViewData inside the controller?)
I would pass the data as a parameter to the GetCountries method. The htmlHelper function really shouldn't know about the properties of your base controller - what if someone were to ever use it on a controller that doesn't inherit from your base? I know I know, you control the code, blah blah. If you're really interested in best practices, avoid the dependency.
public static IEnumerable<SelectListItem> GetCountries(this HtmlHelper html, Countries countries) {
return from c in countries
order by c.Name
select new SelectListItem
{
Text = c.Name,
Value = c.ID
};
}
then, in your View:
<%=Html.GetCountries(this.Entities.Countries)%>
Check out the ViewModel pattern, it's mentioned in the NerdDinner tutorial: http://nerddinnerbook.s3.amazonaws.com/Part6.htm
Basically you create a ViewModel class that encapsulates all the data you might need for your view. So you'd have a class that contains a list of all cities and/or countries, and whatever else, instantiated/populated in the controller action.
Then, you can strongly type your view to use that ViewModel class, and blammo: you've got all the data you need for your form.
I think html helper should return html.
So you have two approaches:
first, if you want to do this as you started, from your htmlhelper prepare your list of elements and then call html.RenderDropDown with initialized list, selected element etc...
second, you can all prepare in your model, so controller will pass initiated object with all elements you need so in you view you can call renderdropdown directly
cheers
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I know next to nothing about MVC so my question might look a bit basic but here it is anyway : is it a good practice to have the same name for the method returning the view and the one saving the data ?
I see a lot of examples like this one where the overloaded "Create" does both jobs. Here's a snippet:
//
// GET: /Customer/Create>
public ActionResult Create()
{
return View();
}
//
// POST: /Customer/Create>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
try
{
// TODO: Add insert logic here>
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I personnaly find it confusing when overloads do completely different things depending on which I decide to choose. So what do you think ? Is it really the "best practice" to roll that way?
Yes, the GET and the POST in this case usually share the same name, because they relate to the same user action.
See Action Naming Convention for more guidance on Action naming.
I personally find it confusing when overloads do completely different things depending on which I decide to choose.
Do they really? They are both concerning the same entity (a Customer). What you can do is name methods whatever you want and then add the [ActionName] attribute and that will be the name of the action. But yes. it's an MVC convention to name them the same way and then pick one or the other depending on whether you're using GET or POST.
Yes if it is the POST method for that view then you should stick to the same name. The only time you should not follow this convention would be if you have multiple different POST methods for the same view for some reason or if you have a POST method which is used by multiple different views.
To provide a standard example:
You have a Create view which is used to create users. There is a HTTPGET Create() action and a HTTPPOST Create() action for posting the user details to the server. In this case you should use the same name.
You have a Dashboard view which displays some data from the database. You have some javascript which uses ajax to retrieve data from the server. In this case you may consider using a different name. E.g. GetData()
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I m working in MVC and some one recently has reviewed my code. On some places in my controller actions I was returning to other views, for example in below code in Index action I m returning to List view:
public virtual ActionResult Index(Student student)
{
// Logic
return View("List", student);
}
Why it is not a good practice ? I did not get any idea why this is wrong. Kindly guide me so I can correct this.
There is nothing wrong with returning a different view to the default action view. The only thing I can think that might be unsettling to some is it does not following the MVC paradigm of convention over configuration.
This may make it difficult to follow someones code if they have lots of actions with names that are different to their corresponding view names i.e:
public ActionResult Index(int id)
{
//logic
return View("StupidName");
}
Convention would have you think the index action would return the Index view, although it doesn't and now the programmer has to go look for the StupidName view. This may seem harmless for one action but if someone has written multiple actions that return differently named views it can be difficult to follow the flow of the project.
Alternatively you could ask the code reviewer why he thinks it is a bad practice. Communication is key in a team.
Personally I see nothing wrong with this as long as the logic for compiling the input for the view isn't duplicated.
If you have to copy a lot of code to ensure that the model for the view is correct, and this isn't really the responsibility of your action, you'd rather redirect to the action instead of calling the view directly.
If this is not the case, or there is a very specific situation, I don't see why this is a problem.
Consider these examples:
You have a error dialog view. If the model just consists of a single property defining the message, it is no problem to call the view directly;
If you have the same dialog, but in order to create the model you have to fetch some general information from the database, have some custom logic, etc., then it is probably best to call the (or create an) action doing this all for you. Also, the number of calls to that view may matter in your decision.
Try this :
public virtual ActionResult Index(Student student)
{
// Logic
return RedirectToAction("List");
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
Can someone point me in the right direction of the correct feature in Grails to implement dynamically changing attributes in my views? For example, when an instance of a domain class is in a particular workflow step, I want certain field prompts, button labels, and data modify-ability to be specific for that step. I will probably store these attributes in another domain class, but I am not sure how to apply them when I am executing, say, the edit method on the instance of data. Is that were custom tags come in, or do I just replace all those attributes in my views with variable tags and pass the values in from the controller? A search term to get me started is fine. Thanks.
Within a controller action you can return a model (Map). The data from this model can be read within views:
class MyController {
def test() {
return [myData: 'hello', myOtherData: 42]
}
}
Within the view you can access the model in the following way:
...
<h1>${ myData }</h1>
<g:if test="${ myOtherData == 42}">
<p>${ myOtherData }</p>
</g:if>
...
If you want to return another view with a model from a controller you can use the render method:
render view: 'myview', model: [myData: 42]
See the section Models and Views from the grails documentation for more details.
Thanks for your reply #micha. Specifically, I am wondering what the best practice is for dynamically changing the visual aspects of a page(view). I think I answered my question by looking at the views from a dynamically scaffolded domain. For example, field prompts are all in the form:
<label for="last">
<g:message code="employee.last.label" default="Last" />
</label>
So you can calculate what all the prompts need to be in your controller/service, or query them from a database, and pass them in along with the data that goes into the fields. I was just checking if Grails anticipated this need and made it easier through some specific aspect of the architecture.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
ASP.NET MVC - View with multiple models
Using ASP.NET MVC 3.0, how can I pass multiple data models from my controller to my view? I'm hoping for an elegant solution...thanks!
BTW - I can provide code samples but I think this is generic enough not to warrant it
There isn't a truly elegant way to do it, unfortunately. My preferred method is to encapsulate the two objects and send that to the view.
public class City{
public Mall TheMall;
public School TheSchool;
}
Then your view will be strongly typed as City, and you will use Model.TheMall.Property and Model.TheSchool.Property to access what you need.
Another method is to use the ViewData bag. What you can do is populate it like such:
ViewData["City"] = "Toronto"; //random string
ViewData["Mall"] = new TheMall(...);
return View(MyViewName);
And then in your view, you will have access these using the key you assigned in the controller ("City", "Mall", in this case).
Hope that helps!
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
This is a general design question: How would you implement a dynamic (runtime generated) form in ASP.NET MVC?
Here's the situation:
A site admin can define form parameters (fields, type of fields, validation) with a GUI (MVC view).
As needed, the runtime generates the form for the end user based on the admin configuration. I'm assuming that all of this logic would reside in the controller - or perhaps extension methods, action filters or something like that.
End user fills out the form, hits submit, information is captured in database.
The customization does not need to support nested controls, 3rd party controls and so forth, but I suspect a very elegant design would allow for that. Mostly, I just need the admin to be able to specify additional fields as textboxes, checkboxes, radio buttons and comboboxes. I will also need the application to allocate a space for this data to be saved in the db, but I believe I have that part figured out.
Thanks for the help.
I had the same need in a recent project. I created a class library for this. I just released a new version of the library.
Maybe it can help you:
ASP.NET MVC Dynamic Forms
You can do this very easily using my FormFactory library.
By default it reflects against a view model to produce a PropertyVm[] array, but you can also create the properties programatically, so you could load settings from a database then create PropertyVm.
This is a snippet from a Linqpad script.
```
//import-package FormFactory
//import-package FormFactory.RazorGenerator
void Main()
{
var properties = new[]{
new PropertyVm(typeof(string), "username"){
DisplayName = "Username",
NotOptional = true,
},
new PropertyVm(typeof(string), "password"){
DisplayName = "Password",
NotOptional = true,
GetCustomAttributes = () => new object[]{ new DataTypeAttribute(DataType.Password) }
}
};
var html = FormFactory.RazorEngine.PropertyRenderExtension.Render(properties, new FormFactory.RazorEngine.RazorTemplateHtmlHelper());
Util.RawHtml(html.ToEncodedString()).Dump(); //Renders html for a username and password field.
}
```
Theres a demo site with examples of the various features you can set up (e.g. nested collections, autocomplete, datepickers etc.)
Another option is to have a very loosely coupled database schema.
//this will contain all the fields and types that the admin user sets
**ApplicationFields**
FieldName
FieldType
...
//these are all the values that have some mapping to a ParentObjectID
**FormValues**
ParentObjectID
FieldName
FieldValue
When you submit your runtime generated View (from ApplicationFields) then just loop through your FormCollection and try and set it on the ParentObject you need to update.
public ActionResult MyForm(FormCollection form)
{
//this is the main object that contains all the fields
var parentObject;
foreach (string key in form)
{
parentObject.SetValue(key, form[key]);
}
...
Then your parentObject might be something like this...
public partial class ParentObject
{
IList _FormValues;
public void SetValue(string key, string value)
{
//try and find if this value already exists
FormValue v = _FormValues.SingleOrDefault(k => k.Key == key);
//if it does just set it
if (v != null)
{
v.Value = value;
return;
}
//else this might be a new form field added and therefore create a new value
v = new FormValue
{
ParentObjectID = this.ID,
Key = key,
Value = value
};
_FormValues.Add(v);
}
}
One way to do this is to create your own ModelBinder which would be at the heart of your generated forms. A modelbinder is responsible for validating the ModelState and rebuilding the typed ViewDataModel (assuming your views are typed).
The DataAnnotations model binder could be a good reference for this what this custom modelbinder allows you to do is via Attributes on your ViewDataModel describe the attribute's validation (and hint at UI rendering). However this is all defined compile time but would be a great reference to start off writing a custom modelbinder.
In your case your model binder should get the validation for a field at runtime from an xml file/string.
If you have a route like:
routes.MapRoute(null, "Forms/{formName}/", new { action = "Index", controller = "Forms", formName = ""}),
Then you could locate the correct form xml in FormsController.Index(string formName) and pass it to the view.
The FormsModel should hold all the possible methods to get data I dont see any other way around this. The Xml could map to a function name (possibly even arguments) that you can invoke using reflection on the FormsModel to fill the ViewData or typed ViewDataModel with data.
The view for Form Index could generate a form from that xml through an HtmlHelper Extension that takes an XmlDocument.
Then when you (or asp.net mvc) binds your form to your ViewData your custom model binder is invoked it can inspect the current controller values to look for the formName and look up the corresponding xml that holds all the validation rules. The ModelBinder is then responsible for filling up ModelState with any runtime defined errors.
It's a hard task but when pulled off succesfully well worth it in my view :)
Update a better alternative to model data would be a very loose database schema as David Liddle suggests. I'd still go through the trouble of saving it as xml (or someother serialized format) and using that for generating the view and to hold validation rules for a custom ModelBinder so that you have more control on layout and validation of each field.
cottsak's answer is very attractive.
There are at least two client-side XForms engines. Here's one:
https://community.emc.com/community/edn/xmltech
I can't see huge advantages of generating XForms or any other "abstraction" over the HTML comparing with straight forward generation of HTML with "Web Forms 2.0" controls list for model like List<Tuple<Meta, Value>>. Note: on server side you in any case would be obligated to parse results manually to fit it to your structrures.
Searching for "next layer abstractions" is good for rapid development, but see, "generate code" (runtime or build-time) has its own specific. Usually the generating code of "lower layer" is the better solution than generating the "higher abstract layer" code.
So just go and wirte code that generate Web 2 Controls in #Foreach loop.