Binding two objects of the same type in an action - asp.net-mvc-2

I have a page that collects information on two objects of the same type. When the page is submitted the action that handles the processing of the information submitted is attempting to use model binding, something similar to:
public ActionResult Submit(Person parent, Person child)
{
//Do some stuff
}
It manages to bind one of them successfully but not the other. Does anyone have any suggestions/resources etc that could help me get this to work?
If needed I can gut/rename and post the actual code for the various pieces.

The solution to this is very much similar to the solution to my question that I posted the other day (I wouldn't at all call this a dupe though).
What you need to do is just include the parameter name in your inputs, eg:
<%: Html.TextBox("Parent.Name") %>
.....
<%: Html.TextBox("Child.Name") %>
and it should all automagically work.
(I think this is MVC2 only, you didn't mention whether you were using 1 or 2)

Would it make sense to have a ParentChild Model with two person instances in it?
I don't think I've seen any examples like this trying to bind two models on post.

Related

How do I generate a form using a model with single table inheritance?

I have a model Company that has a type field. There are two subclasses Fleet and Dealer.
I know the inheritance is working so I'm now working towards the views working too. However the views/companies/_form.html.erb is producing this error when I click edit on a specific company object on my webpage:
undefined method `dealer_path' for #<ActionView::Base:0x000000000418c0>
Here is the form_with tag:
<%= form_with(model: company, class: "contents") do |form| %>
*CONTENT*
<%end%>
I want to generate the form based on what company type I am looking at and for all the fields to be populated with their corresponding data.
I found this warning on the ROR site (https://guides.rubyonrails.org/form_helpers.html):
When you're using STI (single-table inheritance) with your models, you can't rely on record identification on a subclass if only their parent class is declared a resource. You will have to specify :url, and :scope (the model name) explicitly.
But I do not understand exactly what this means and I believe it is the key to my solution. I wish there was an example of this situation on that guide.
Any help or suggestions are welcome and appreciated!
UPDATE
I changed the form_with tag to be:
<%= form_with(model: [:company #company], class: "contents") do |form| %>
and from my understanding this now generates the URL companies/:id/edit
This is closer, and now brings me to the companies edit page but I can't update now because the changes don't persist.
My NEW question now is, what routes should I have set up?
If I'm on localhost:3000/companies and I click 'show company', should this take me to /companies/id: or take me to /dealer/id: / /fleet/id: ?
I have managed to route the app so it will take me to /companies/id regardless of the type value of the object. This works well and all CRUD is working well now too.
I didn't log exactly what it was I changed this time as I just reverted to a previous commit and rebuilt from there.

Multiple form inputs for the same field

I have a Rails model called request_form. In the form I have multiple boxes that can be selected, similar to the "What can we craft for you section" in the following site http://mostlyserious.io/get-started/
I have a field called number_of_guests that can be a handful of values depending on which section is clicked. I plan on using javascript to grab the value of the clicked element and assigning it to the request_no_of_guest param. However, in the form I have that same field rendered 5 times to allow for each selection. What is the best way about this? Is there a better way to handle this? I thought about creating a controller method that loops through each instance of that request_no_of_guests param and determining which instance is populated and then sending that up.
Is this the best way to handle this case?
Well as you did not provide any useful detail I will answer as I understood the question.
Let’s have a quick look at what this might look like. To do so, we’ll imagine a demo app into which you can enter the name of a professor and select their various areas of expertise.
Professor has a field expertise which is String.
The form can be as follows:
<%= label_tag 'expertise_physics', 'Physics' %>
<%= check_box_tag 'professor[expertise][]', 'Physics', checked('Physics'), id: 'expertise_physics' %>
<%= label_tag 'expertise_maths', 'Maths' %>
<%= check_box_tag 'professor[expertise][]', 'Maths', checked('Maths'), id: 'expertise_maths' %>
alter app/controllers/professors_controller.rb
from
params.require(:professor).permit(:name, :expertise)
to
params.require(:professor).permit(:name, expertise:[])
Then in app/models/professor.rb
before_save do
self.expertise.gsub!(/[\[\]\"]/, "") if attribute_present?("expertise")
end
and in /app/helpers/professors_helper.rb
def checked(area)
#professor.expertise.nil? ? false : #professor.expertise.match(area)
end
This way you can grab the different values selected in the form into the expertise attribute, however this is not recommended if you are planning to query the selected options. The right way would be create a new model called Expertise and then create the relationship professor has_many expertises.
But if you are looking for something simple, then use the above code.

Zend creating forms based on requests within one controller/action

I don't really know how to word the title well, but here's my issue. I decided instead of having 25 controllers to handle pages, I have one PageController with a viewAction that takes in a :page parameter - for example, http://localhost/website/page/about-us would direct to PageController::viewAction() with a parameter of page = about-us. All of the pages are stored in a templates folder, so the viewrenderer is set to render application\templates\default\about-us.phtml.
I did this so I can consolidate and it seemed like a better approach. My question is the following: lets say when the page request is contact-us, I would need a Zend_Form to be used within the contact page. So, I would need a way within PageController::viewAction() to recognize that the page needs to have a form built, build the form, and also upon submission the need to process it (maybe this should be handled in an abstract process method - not sure).
I have no idea how to implement this. I thought maybe I can store a column with the name of a form and a connecting page identifier. Even better, create a one-to-many page to forms, and then in the submission loop through the forms and check if submitted and if so then process it (maybe there is a isSubmitted() method within zend_form. I really don't know how to handle this, and am looking for any help i can get.
Thanks!
Here is something that came to mind that may work or help point you in a direction that works for you.
This may only work well assuming you were to have no more than one form per page, if you need more than one form on a page, you would have to do something beyond this automatic form handling.
Create a standard location for forms that are attached to pages (e.g. application/forms/page). This is where the automatic forms associated with pages will be kept.
In your viewAction, you could take advantage of the autoloader to see if a form for that page exists. For example:
$page = $this->getParam('page');
$page = ucfirst(preg_replace('/-(\w)/ie', "strtoupper('$1')", $page)); // contact-us -> ContactUs
$class = 'Application_Form_Page_' . $page;
// class_exists will invoke the autoloader to map a class to a file
if (class_exists($class)) {
// a form is defined for this page
$form = new $class();
// check if form was posted
if ($this->getRequest()->isPost()) {
if ($form->isValid($this->getRequest()->getPost()) {
// form is valid - determine how to process it
}
}
// assign the form to the view
$this->view->pageForm = $form;
}
All this really leaves out is the action you take to process a specific form. Since the contact form will likely generate an email, and another form may insert data into a database, you will need some sort of callback system or perhaps another class that can be mapped automatically which contains the form processor code.
Anyway something along those lines is what came to mind first, I hope that helps give you some more ideas.

ASP MVC 2 Pattern for implementing CanExecute style commands

I have come from WPF (MVVM) background and trying to shift to MVC 2. Is there any pattern in MVC2 where you can use Commanding/Command buttons like <input> which you use to submit the form so that you can hide/disable when you try to Render the View.
In MVVM world, your commands could implement ICommand interface, and it had CanExecute method which was quite useful. I was wondering if there is anything similar in ASP MVC 2 ?
The only way I can think of, is to do it in the View, so that I can check the flag on ViewModel (CanSave) and depending on that show/hide the <input> tag.
Basically I want to have 2 version of the website running, one in Read-Only mode and the other Editing mode.
Let me know if you need any clarification.
ASP.NET MVC does not feature the notion of 'controls', as are found in classic ASP.NET and WPF. The foundational blocks of ASP.NET MVC are HTML elements, like <input>, <button> et cetera. Naturally, these don't offer the functionality you're looking for (i.e. Implementation of the ICommand Interface).
The scenario that you're looking at (i.e. two modes of your form) can be (and arguably should be) dealt with at the View level. You're already facing the right direction: have a 'CanSave' property on your Model, and use this in the View to determine what is generated.
Example:
<% if (Model.CanSave)
{ %>
<p>First Name: <%= Html.TextBox("firstname", Model.firstname) %> </p>
<% }
else
{ %>
<p>First Name: <%=Model.firstname %></p>
<% } %>
You'll probably want to check out the DisplayTemplates and EditorTemplates... very handy for this scenario. Brad Wilson does a good job here.
It will help you move to this:
<%= (Model.CanSave) ? Html.EditorFor(x => x.firstname) : Html.DisplayFor(x => x.firstname) %>
...which makes your View clean and nice.
If you can't get MVC to do this it's relatively worth it to hand-code something like this vb-style pseudocode. This involves...
Subclassing your controls.
Not as much of a pain as it sounds, but, it is a medium sized one. Therefore it is only appropriate for medium-sized to large apps. But worth it for them.
Interface BaseUIControl
Property Enabled as Boolean
Property Visible as Boolean
Property Name as String
Property EntireStateAsXML as string ' You can use this to do EVERYTHING!
Interface UserActionItem
Event Clicked(sender as UserActionItem ... don't pass anything from UI namespaces!)
Class MyButton (or link, etc.) Implement BaseUIControl, UserActionItem Inherits UI.Button
How does this help? You've basically replaced the missing functionality. Your Controller (or even application layer) can be aware of the UI components by interface only, so they won't have to see the UI types.
more...
You can leverage this philosophy to control everything. This has saved me thousands of hours of monkey code.
Interface TextControl
Property Value as text
Interface CheckControl
Property Checked as boolean
The above two are Pretty basic - you inherit MyCheckBox and MyTextBox from the UI versions and implement the appropriate.
Of course you could set up common code to loop thru all controls and auto-validate (or loop thru and get each one's XML to autobind the whole form).
Interface ValidationBase
Property Required as Boolean
If you have a text or numeric-only mask or restricitons built into 2 subclasses...
Interface ValidationNumeric
Property MinVal, MaxVal as double
Interface ValidationText
Property MinLen, MaxLen as double
No, it won't go to the database for you. But this sweeps a ton of crud under the rug.
You can even set these property values in the UI designer - yes, putting BL in bed with UI, BUT, if you only have one UI for the BL, actually works very well.
Now image a UI with a mix of things like listbox/multiselect, double-list picker controls, checked listbox, a groupbox of option buttons/checkboxes ...
Interface Selector
property Items as list (of string)
property SelectedItems as list (of string)
Use what works on the UI - your generic routines can care less what they look like!! The subclassed UI pieces will just implement them to set/get the right values.
In addition ... we added 'validationEquation', ActivatesEquation (gray/ungray), SetValueTriggerEquation (if true, set value to SetValueEquation, otherwise, leave alone), which allowed controls to be set to simple values from other items (basically getting the values from bound objects as if using reflection) via Pascal Gayane's Expression Evaluator (it reads .net types!)
You can also subclass the main form, have it recurse thru all it's subcontrols, put together the XML's for the whole screen, and serialize it like that. You can have your own classes implement these in the non-UI layers and use it to totally (de/)serialize the UI state, and use them to read the UI too, if they relate to a business object, to map to it.
It's unbelievable how much this simplifies a complex app. We have one with 1200+ data entry panels (... pages... ours is a thickclient app) that will fill out 250 different paper forms at 250K LOC. The form definitions contain the 'name' of each control and this is pulled from the XML generated from the screens. We probably saved 500K LOC as many of the screens have no code behind them or only trivial code; all the databinding, validation, etc. is handled by common routines that reference the interfaces.
Like I say, this only works for a big app. Spend at least 2-3 weeks developing 90% of the functionality, though; probably another month throughout the 2 years dev maturing it. I am guessing your apps is big if you're caring about ICommand and its conveniences. I would put the payback at 15-20 moderately complex pages.
If I'm understanding the question correctly, you could write a ControllerCommand class to encapsulate this. Something like this:
public class ControllerCommand
{
public string Action { get; set; }
public string Controller { get; set; }
public object RouteValues { get; set; }
public bool IsEnabled { get; set; }
}
Your Details viewmodel might use it like this:
public class DetailsModel
{
public guid Id { get; set;}
// some other viewmodel properties
public ControllerCommand Edit { get; set; }
}
You could write extension methods on HtmlHelper to replace the built-in ones:
public MvcHtmlString CommandLink(this HtmlHelper html, string linkText, ControllerCommand command, object htmlAttributes)
{
if (command.IsEnabled)
{
return html.ActionLink(linkText, command.Action, command.Controller, command.RouteValues, htmlAttributes);
}
else
{
return MvcHtmlString.Create(linkText);
// perhaps return <span class="disabled-command">linkText</span>
}
}
One of the ways I have found is to use Filter attributes which you can put in your Actions, but that only handles CanExecute on the server side.
For the GUI side, couldnt find better way than putting If statements to check if the user is Priviliged to run particular action (i.e. Edit/Delete buttons)

Asp MVC 2: Typed Editor Template

(I reference this tutorial in this text)
I want to use the Html.EditorFor (or Html.Editor) helpers.
If a UserControl needs additional data it is passed via
...EditorFor(model => model.Album, new { Artists = Model.Artists, ... })
In the UserControl it's accessed via ViewData[stringKey], ie
... new SelectList(ViewData["Artists"] as IEnumerable, ...
To me this smells a little fishy as I would prefer a strongly typed ViewModel which ensures that specific data is available.
I'm now a little bit stuck as I don't know wheater there's a "typed way" to find or I should accept this way as-is.
How did you solve this issue? Any help appreciated!
Lg
warappa
I would probably change my view model so that I don't need to pass this additional information. You could make for example an album has a collection of artists. Now all tha you will have to do is:
<%: Html.EditorFor(model => model.Album) %>
And in your editor template:
<%: Html.DropDownListFor(x => x.SelectedArtist, new SelectList(Model.Artists)) %>