I am well aware that you use underscores for data attributes with hyphens ("data_bind" instead of "data-bind", in the object), and they automatically get replaced with hyphens. But I have run into the problem where you can't do this underscore "hack," if the attribute ends with "name". So I have tried both of these, but neither work:
#Html.TextBoxFor(model => model.Street, new { data_encrypted_name = "street" })
#Html.TextBoxFor(model => model.Street, new { #data_encrypted_name = "street" })
When I view the HTML that is generated, for both cases above, it generates:
<input data-encrypted- id="ViewModel_Street" name="ViewModel.Street" type="text" value="" />
At first, I thought this might have something to do with multiple underscores/hyphens, but I tried two more test cases, to see what would happen, and they both worked just fine:
#Html.TextBoxFor(model => model.Street, new { data_encrypted_namme = "street" })
#Html.TextBoxFor(model => model.Street, new { data_name_encrypted = "street" })
So this problem is definitely related to having "name" at the end of the attribute.
Am I doing something wrong or missing something, or is this a bug in how .NET converts the attributes?
(For clarification, we use Braintree Payments, and they require the use of the "data-encrypted-name" attribute on certain inputs, so we can't just choose another attribute name.)
Thanks to Tommy for testing the behavior I described and finding it wasn't a bug for everyone.
After Tommy wrote this, I looked at the Helper we were using. I realized that we were actually using an Extension method called "NameLessTextBoxFor" (which we found here: How to extend html.textboxfor to remove the name attribute?), which removes the name="" attribute from the input before displaying it. I should have confirmed this before posting, but didn't recognize it could affect the HTML attributes passed into it.
And lo and behold, as you would probably expect, the functionality of this method was also cutting off any attribute that contained name="". It was doing a very simple search and replace on that text and removing it. So that was the issue here.
Thanks for your time and attention to this issue and apologize I didn't catch this myself.
Related
I am developing a web application in Cl-who, Hunchentoot, and Common Lisp that will need to process customer orders. Since they could obviously order more than one item, I figured a Checkbox would make the most sense. However, the issue is when I define an easy-handler, it doesn't receive the array of results like an array in PHP if you have a series of Checkboxes with the same name and different values. Instead, it treats the variable as a String, so I cannot iterate over each Box that was checked. Here is a snippet of my code:
(:input :type "checkbox" :name "food[]" :value "cheese balls")
(:input :type "checkbox" :name "food[]" :value "fries")
(:input :type "checkbox" :name "food[]" :value "hamburger")
Here is the handler I have set up (maybe I need to use the loop macro here?) This is just a sample because I will obviously process each argument passed to the easy-handler when I figure out this problem:
(define-easy-handler (process-order :uri "/process-order")
(customer-name customer-address customer-city customer-phone order-type food[])
(standard-page (:title "order results"
:href "file.css")
(:h1 (if food[]
(dolist (x food[])
(:li (fmt "We see that you want ~A~%" x)))))))
Those are just three potential inputs that someone could check. So lets assume that a customer checks all three... Only cheese balls would return because Lisp is treating the name "food[]" as an individual string. What I mean by that is that in PHP that variable for name ("food[]") would be processed as if it were an array. So in HTML and PHP it would look something like this:
<input type="checkbox" name="food[]" value="cheese balls" class="check"/>
<input type="checkbox" name="food[]" value="fries" class="check"/>
<input type="checkbox" name="food[]" value="hamburger" class="check"/>
Assuming a customer selected all three Checkboxes, I could do something similar to this in PHP:
if( isset( $_POST['food'])) {
foreach ( $_POST['food'] as $food){
echo $food;
}
}
It is not clear how you'd achieve similar functionality in Common Lisp with Cl-WHO and Hunchentoot however. The only other alternative I can think of is passing like 30 parameters to the easy-handler, but that sounds like the least efficient way to solve this problem. I know that there is also a CL form processing library, but I was hoping to avoid going down that route, although I will if that's the only possible solution. Giving each checkbox a different name seems like the worst possible way to solve this.
After further reading the documentation, you can alter the parameter type that the easy handler expects to receive. As soon as it sees that it is a list in the parameter definition, it treats it as a List. I simply changed my food parameter to this:
(food[] :parameter-type 'list)
And it treats it as if it where a list and retrieves multiple results from my CheckBoxes.
I've found myself working on a .Net MVC3 project and sorely missing having Formtastic available in my rails apps.
Are there any good .Net MVC replacements for Formtastic?
I suggest using MVC3s HTML Helpers.
#model mynspace.MyModel
#Html.EditorForModel()
This html helper generates editor fields for every field in your model, choosing the most likely option. Editing the Editor template, you can change the way it is layed out as well. See this question on changing the template
It can of course be used more customizable by each field with things like:
#Html.Label("Daily Rate")
#Html.EditorFor(model => model.DailyRate)
#Html.ValidationMessageFor(model => model.DailyRate, "Please enter a valid Daily Rate (2 d.p.)")
This can be custom layed out by putting tags around it, i.e. things like <p> or <td>
You can also force an input type using options like:
#Html.TextBoxFor(model => model.DailyRate)
#Html.CheckBoxFor(model => model.DailyRate)
#Html.DropDownBoxFor(model => model.DailyRate, ViewBag.DailyRates)
see here for a full list of options
I have a project called FormFactory that lets you do much of the stuff formastic does http://formfactory.apphb.com/
It transforms model objects into PropertyVm objects, which are a viewmodel for an input basically. You could manually create the PropertyVms if you want.
This problem has been killing me. I played around with Ryan Bates complex forms, but I can't quite figure out my problem.
I have this schema:
Location has_many :targets
Target has_many :target_classifications
All locations are shown on the page. A user may create a target for any location dynamically through jscript, which then adds a table row under the location 3 selects (that contain available classifications to the target) and a target value. Any number of targets can be created for any location before clicking save.
I'm using rjs to render a target_partial, which has this code:
I'm using fields_for in this way:
for each select. When sumbmitted, I get this hash:
"new_targets"=>
{"7"=>[{"id"=>"13"}, {"id"=>"15"}, {"value"=>"67", "id"=>""}],
"4"=>
[{"id"=>"12"},
{"id"=>"15"},
{"value"=>"23", "id"=>""},
{"id"=>"11"},
{"id"=>"16"},
{"value"=>"67", "id"=>""}]},
So, it separates each target by location ("7" and "4" in this case), but doesn't separate each target. What I want is this:
"new_targets"=>
{"7"=>[
{"target"=>[{"id"=>"13"}, {"id"=>"15"}, {"tonnes"=>"67"}]}
],
"4"=>[
{"target"=>[{"id"=>"12"},{"id"=>"15"},{"tonnes"=>"23"]},
{"target"=>[{"id"=>"11"},{"id"=>"16"},{"tonnes"=>"67"]}
]
}
so I can iterate through each target for each location. I can't seem to add in a new [target] brace in my field_for method (it blows up), but that's kind of what I want to do. Any thoughts?
I don't know if you are doing this, but you need to specify a string instead of the object when using fields_for. I can't see the codes you have in your partial, so I may be way off. Anyway, the way I do it is in a helper:
def fields_for_target(target, &block)
prefix = target.new_record? ? 'new' : 'existing'
fields_for("location[#{prefix}_target_attributes][]", target, &block)
end
This sort of issue is discussed here:
http://wonderfullyflawed.com/2009/02/17/rails-forms-microformat/
But it seems to be a rails 2.3 solution (not an option for me). Basically, I want a form like they've posted on the site:
<input name="creator[widget_attributes][0][id]" />
<input name="creator[widget_attributes][0][name]" />
<input name="creator[widget_attributes][0][price]" />
<input name="creator[widget_attributes][1][id]" />
<input name="creator[widget_attributes][1][name]" />
<input name="creator[widget_attributes][1][price]" />
Just some way to create a unique identifier for each target (or in this case, widget attribute) I want to add. Kind of tough given that a new target is added with jscript. I feel like there should be some way for rails to automatically do this for me
Easy. Look up accepts_nested_attributes_for. :)
I have modified the Nerd Dinner application to allow editing of child records by adding the following code to the DinnerForm.ascx
<p>
<%int i = 0;
foreach (NerdDinner.Models.RSVP rsvp in this.Model.Dinner.RSVPs)
{ %>
<%= Html.Hidden("Dinner.RSVPs[" + i + "].RsvpID", rsvp.RsvpID)%>
<%= Html.Hidden("Dinner.RSVPs[" + i + "].DinnerID", rsvp.DinnerID)%>
<%= Html.TextBox("Dinner.RSVPs[" + i + "].AttendeeName", rsvp.AttendeeName)%>
<% i += 1;
} %>
</p>
it is rendering this:
<p>
<input id="Dinner_RSVPs[0]_RsvpID" name="Dinner.RSVPs[0].RsvpID" type="hidden" value="36" />
<input id="Dinner_RSVPs[0]_DinnerID" name="Dinner.RSVPs[0].DinnerID" type="hidden" value="63" />
<input id="Dinner_RSVPs[0]_AttendeeName" name="Dinner.RSVPs[0].AttendeeName" type="text" value="kp" />
<input id="Dinner_RSVPs[1]_RsvpID" name="Dinner.RSVPs[1].RsvpID" type="hidden" value="37" />
<input id="Dinner_RSVPs[1]_DinnerID" name="Dinner.RSVPs[1].DinnerID" type="hidden" value="63" />
<input id="Dinner_RSVPs[1]_AttendeeName" name="Dinner.RSVPs[1].AttendeeName" type="text" value="jim" />
</p>
I have not modified the DinnersControler's Post Edit Action method. The Parent dinner is getting updated as usual, but it appears the UpdateModel(dinner); is not seeing/updating the child RSVP records.
I have tried a few variations on rendering the child records so that the Model binders will see the collection, with no luck.
Is updating parent/child records in one shot by calling UpdateModel(Parent); possible with the current model binders?
I haven't been able to do this myself.
I know that you can update a single child element, ie, Dinner.RSV automatically. I've never seen the ability to update a child enumerable, which would require the binding to know which property is the ID and look for it (ie, Dinner.RSVP.Where(r => r.RSVP_ID == input_id) and then update that). I don't know enough about custom binding to do something like that.
However, what I have done is to do a loop and specify the rsvp and the int as a prefix:
So you do:
UpdateModel("Dinner", Dinner);
to update the parent and then:
int i = 0;
foreach (var r in Dinner.RSVPs) {
UpdateModel(r, "Dinner.RSVPs[" + i++ + "]");
}
Not quite as clean, but it works well for me. It might take a bit more effort to build in validation, though (you want to validate all at the same time, and make sure you don't jump back to the view on the first RSVP with an error).
EDIT: Fixed the code to reflect the OP's solution, including a bug in my parameter order. With that being said, I'm more comfortable using the RSVP.ID property than a running integer. As long as you know that Dinner.RSVPs will be the same on the POST as the GET (I'm confident of this in my code), then using the RSVP.ID will work. Should RSVPs be different, then only those present on both will get updated. However, using the sequential int could potentially cause the wrong object to be updated.
Hope that helps,
James
Ok, so nobody's answering. I don't know the nerddinner app but was interested by your problem. Was hoping to see some answers but, well, none yet. Not 100% sure because of lack of familiarity with ndinner, but could it be related to this post where they mention binding/updating only when a property is explicitly passed?
Your question is whether updating parent/child records in one shot by calling UpdateModel(Parent); possible with the current model binders?
Yes, this is possible. However, it is not possible (without some minor workarounds) if you are using Linq-to-Sql and your child objects are exposed via EntitySet<T> instead of something like IList<T>. I believe this will be (has been?) addressed in the next version of MVC due out with ASP.NET 4.0. For the time being, though, the MVC default model binder does not seem to understand how to work with EntitySet.
Please see this other answer I wrote on a related question some time ago, with details about how I am now dealing with (working around) this situation in certain simple cases. In doing this, I've had to stop worrying so much about how "ideal" this solution is from a DDD/OOP perspective, as a trade-off to simply getting MVC and LTS to play together nicely with minimal effort.
Note, I will admit that James S's solution is probably more "pure," but in order to do this in "one shot" as you ask, you'll need to either wait for ASP.NET 4.0, or use a workaround similar to what you'll find in my other post.
Good luck!
I am noticing a weird issue when using ModelState.AddModelError to validate input on my forms. The output from Html.ValidationMessage is not the true HTML value but it's encoded value and so the CSS style is not applied to the error message.
Example:
private string errorMessage = "<span class=\"negative\">{0}</span><br class=\"hid\" />";
ModelState.AddModelError("title", String.Format(errorMessage, "Tab title is required"));
The output is shown as:
<span class="field-validation-error"><span class="negative">URL is Required</span><br class="hid" /></span>
This didn't use to be the case with their earlier beta's and I am not sure what approach to take here.
Thanks
Nick
There is another way to do it, too, without having to create your own extension.
Say for instance we have the following in one of our controllers:
ModelState.AddModelError("Name", "<b>Please Use a Valid Person Name</b>");
We can then do the following in our view:
#if(Html.ValidationMessageFor(x => x.Name) != null){
#Html.Raw(Html.ValidationMessageFor(x => x.Name).ToString())
}
The will prevent the error message of '<b>Please Use a Valid Person Name</b>' from being encoded.
Create your own extension method that mimics Html.VallidationMessage...?
I had to do something similar because the built in MVC validation stuff (ModelState, ValidationMessage etc etc) doesn't cater for pages that have more than one form on a page.