4

I have a project written in C# MVC using Razor templates. On one of my pages I have several input fields that contain numeric values. The Razor code that sets the values of these input fields looks like this:

@Html.Editor(Model.DesignParams[i].ParamId,
new {
    htmlAttributes = new
    {
        @Value = Model.DesignParams[i].DefaultValue,
        @class = "form-control text-right",
        @type = "text",
        id = "_" + Model.DesignParams[i].ParamId,
        uomid = Model.DesignParams[i].UOMId,
        measureid = Model.DesignParams[i].MeasureId
    }
})

The above code works fine using FireFox and Chrome and generates an input field that looks like this:

<input type="text" uomid="MBH" name="HeatOfRejection" measureid="HeatLoad"
       id="_HeatOfRejection" class="form-control text-right text-box single-line"
       value="5000.0">

But the same Razor code, identical @Model values viewed with IE generates this:

<input Value="5000" class="form-control text-right text-box single-line"
       id="_HeatOfRejection" measureid="HeatLoad" name="HeatOfRejection" 
       type="text" uomid="MBH" value="" />

As you can see, there is a difference between the value= attribute generated for IE in that the value attribute that gets my actual value begins with an uppercase 'V' and the lowercase value is an empty string. I'm stumped on this...

Can anyone tell me why this is happening and possibly how to handle it?

This difference effects jQuery's ability to return the input's value with:

var value = $(inputfield).attr("value");

Maybe .val() will retrieve the input field value, but this is going to require a rewrite of core jQuery code that supports this page and others, so I wanted to ask if anyone can tell me why this 'Value=' gets created for IE only and if there is a way of overcoming the problem.

Update:

Changing @Value to @value (or just value) results in an empty value attribute in Firefox and IE:

<input type="text" value="" uomid="MBH" name="HeatOfRejection" measureid="HeatLoad" 
       id="_HeatOfRejection" class="form-control text-right text-box single-line">
abatishchev
  • 98,240
  • 88
  • 296
  • 433
rwkiii
  • 5,716
  • 18
  • 65
  • 114
  • Why would you bind to property then try and override its value with the value of another property. Just set the value of `ParamId` to the value of `DefaultValue` in the controller before you return the initial view. A side effect of your code would be that a user enters a value (say 4000.0) then submits. If you returned the view because of (say) validation errors, the user's value would be overwritten with 5000.0 - sure way to annoy the users of your site. –  Dec 19 '14 at 08:03

4 Answers4

3

You are "capitalising" the value html attribute. Change this to lower case...

 @Value = Model.DesignParams[i].DefaultValue

as below ...

@value = Model.DesignParams[i].DefaultValue

IE is not the smartest of web browsers and there's definitely something wrong in the way Trident (they're parsing engine) validates elements' attributes as seen in these threads...

https://github.com/highslide-software/highcharts.com/issues/1978

Highcharts adds duplicate xmlns attribute to SVG element in IE

Also, as already noted somewhere else. What's the need for the Editor extension method? Isn't it simpler to just use TextBoxFor instead?

@Html.TextBoxFor(model => model.DesignParams[i].ParamId
    , new 
        { 
            @class = "form-control text-right"
            , uomid = Model.DesignParams[i].UOMId
            , measureid = Model.DesignParams[i].MeasureId 
         })
Community
  • 1
  • 1
Leo
  • 14,625
  • 2
  • 37
  • 55
  • I should have noted that this was my first instinct, but the then my value doesn't get set in the `value=` field for any browser and ends up being 0. I wish setting @Value to @value resolved the problem. – rwkiii Dec 19 '14 at 04:20
  • No... I have changed it to all lowercase (@value) and also tried @StuartLC answer making it `value` without the '@', but then I get `value=""` rendered in IE and Firefox. – rwkiii Dec 19 '14 at 04:49
  • @Leo I don't think IE is really to blame here for not knowing what to do with two attributes of the same name. At least it treats the attributes with different capitalization as separate attributes instead of pretending they're the same attribute as the other browsers do. – JLRishe Dec 19 '14 at 06:00
  • @JLRishe it's totally the opposite, if we were to blame anyone it'd be IE for not following standards which clearly states that attributes are case-insensitive, therefore `Value` is the same as `value` – Leo Dec 19 '14 at 06:25
  • @Leo Do the standards say anything about what the browser should do when there are two attributes with the same name in different capitalizations? I'm guessing that's a gray area. Seems to me that IE is doing its best to accommodate the page's bogus markup as well as possible. When there aren't duplicates, IE correctly treats attributes as case-insensitive. – JLRishe Dec 19 '14 at 07:29
  • @JLRishe yes, they do clearly specify it...it's nothing new. `4.1.1 In content implemented using markup languages, elements have complete start and end tags, elements are nested according to their specifications, elements do not contain duplicate attributes, and any IDs are unique, except where the specifications allow these features. (Level A)` – Leo Dec 19 '14 at 07:55
  • @JLRishe BTW, I'm not endorsing writing bogus markup and I'm not an advocate for any browser. I'm just stating something that is a fact. Anyway, the question is not about HTML standards – Leo Dec 19 '14 at 07:58
  • @Leo The WCAG that you cited is a series of guidelines for publishing accessible web content. It doesn't say anything about how user agents should handle non-conformant markup. – JLRishe Dec 19 '14 at 08:05
  • @JLRishe geez man, you're really getting hilarious. So, what's your point? That duplicate `value` attributes are allowed in `input` tag elements? So, you reckon that it is valid html? And that html validators will let you get away with that? Mate, I don't know from what school you came from but really, do your own research, you don't really have to believe me...seriously... – Leo Dec 19 '14 at 12:12
  • @Leo At what point did my use of the term "bogus markup" give you the impression that I thought duplicate `value` attributes were valid HTML and that validators should allow them? My point is that it's _not_ valid HTML and that whatever a browser does with them (within reason) is fair game. I haven't seen any specification of what a browser is expected to do in that situation, and if you're so sure that it's a cut and dry case, then please show me something to back that up. – JLRishe Dec 19 '14 at 12:32
  • @JLRishe obviously you must have a very boring life. If you have nothing to do with your life, how about you look it up? BTW, don't even bother to reply mate, I'm over your babbling rubbish – Leo Dec 19 '14 at 14:28
  • @Leo Thanks for the ad hominems and baseless assertions, bro. If this is the way you react to someone disagreeing with you, I'm glad I don't have to interact with you IRL. Have a nice day. – JLRishe Dec 19 '14 at 14:34
3

As StuartLC points out, you are trying to get Html.Editor to do something it wasn't designed to do.

What happens when you pass a @value or @Value key to the htmlAttributes is that the rendering engine produces an attribute with that name in addition to the value attribute it's already generating:

<input type="text" name="n" value="something" value="somethingElse" />

or

<input type="text" name="n" value="something" Value="somethingElse" />

In both cases, you're giving the browser something bogus, so it can't be expected to exhibit predictable behavior.

As alluded above, Html.Editor has functionality to generate the value attribute based on the expression argument you pass to it. The problem is that you are using that incorrectly as well. The first argument to Html.Editor() needs to be an expression indicating the model property that the editor should be bound to. (e.g. the string value "DesignParams[0].ParamId") Nowadays, the preferred practice is to use the more modern EditorFor that takes a lambda function, as StuartLC showed in his post:

@Html.EditorFor(model => model.DesignParams[i].ParamId, ...)
JLRishe
  • 99,490
  • 19
  • 131
  • 169
2

You shouldn't be using invalid Html attributes in this way. Use the data- attributes in Html 5.

Also, your use of @Html.Editor(Model.DesignParams[i].ParamId (assuming ParamId is a string) deviates from the helper's purpose, which is to reflect the property with the given name off the Model, and use the value of this property as the Html value attribute on the input. (MVC will be looking for a property on the root model with whatever the value of ParamId is, which seems to silently fail FWR)

I would do the defaulting of Model.DesignParams[i].ParamId = Model.DesignParams[i].DefaultValue in the Controller beforehand, or in the DesignParams constructor.

@Html.EditorFor(m => m.DesignParams[0].ParamID,
   new {
      htmlAttributes = new
        {
            // Don't set value at all here - the value IS m.DesignParams[0].ParamID
            @class = "form-control text-right",
            @type = "text",
            id = "_" + Model.DesignParams[i].ParamId,
            data_uomid = Model.DesignParams[i].UOMId,
            data_measureid = Model.DesignParams[i].MeasureId
        }

Note that this will give the input name as DesignParams[0].ParamID, which would be needed to post the field back, if necessary.

Here's a Gist of some example code

(The underscore will be converted to a dash) Use data() in jQuery to obtain these values:

var value = $(inputfield).data("uomid");
Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • Thank you for this. It's very helpful. Are you saying that you think this will fix the issue I posted? I mean, you are likely pointing me to the 'proper' way of handling my custom attributes. It's good advice, but do you think it will resolve the issue? – rwkiii Dec 19 '14 at 04:26
  • [Data attributes](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_data_attributes) in html 5 provide a standard way of appending custom attributes to html elements, without resorting to hacking our own custom attributes. And the jQuery support via data makes it simple to scrape them off (remember to omit the `data-` prefix with `.data()`) – StuartLC Dec 19 '14 at 04:32
  • @rwkiii I've added some sample Gist code to give alternative ideas on using creating the input field, with the value correctly set. – StuartLC Dec 19 '14 at 05:47
2

Editor works with metadata. then you need to more about this, http://aspadvice.com/blogs/kiran/archive/2009/11/29/Adding-html-attributes-support-for-Templates-2D00-ASP.Net-MVC-2.0-Beta_2D00_1.aspx

But the easiest way is go with

@model Namespace.ABCModel

@using (Html.BeginForm("Action", "Controller", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
 @Html.TextBoxFor(model => model.DesignParams[i].ParamId, new { @class = "form-control text-right",     uomid = Model.DesignParams[i].UOMId, measureid = Model.DesignParams[i].MeasureId })
}