3

Closed

Razor outputs the string "value" or completely removes value attribute instead of True or False for booleans when building input fields without using helper methods.

description

I was creating some views where I used html for all my input fields instead of using the helper methods. I had some hidden fields that contained boolean values. I've done this often in MVC 3 and it was never a problem, but in MVC 4 Razor if the value of the boolen is true then it outputs the string "value" if the boolean is false then it completely removes the value attribute from the input.

I created a small test application using the basic webapplication template in VS2012,

ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace target45.ViewModels
{
    public class IndexViewModel
    {
        public bool test1 { get; set; }
        public bool test2 { get; set; }
        public bool test3 { get; set; }
        public bool test4 { get; set; }
    }
}
Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using target45.ViewModels;

namespace target45.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            IndexViewModel model = new IndexViewModel()
            {
                test1 = true,
                test2 = false,
                test3 = true,
                test4 = false
            };
            return View(model);
        }
    }
}
View:
@model target45.ViewModels.IndexViewModel

@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
    bool test = true;
}

<div>
    <h2>test 1</h2>
    <input type="hidden" value="@Model.test1" />
    <input type="text" value="@Model.test2" />
    <input type="password" value="@Model.test3" />
    @Model.test4
    @test
    <input type="text" value="@test" />
    <input type="text" value="@false" />
</div>
<div>
    <!-- Shows that Razor acts correctly after invalid html -->
    <h2>test 2</h2>
    <" />
    <input type="hidden" value="@Model.test1" />
    <input type="text" value="@Model.test2" />
    <input type="password" value="@Model.test3" />
    @Model.test4
    <input type="text" value="@test" />
    <input type="text" value="@false" />
</div>

Outputted HTML:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <link href="/Content/site.css" rel="stylesheet"/>

    <script src="/Scripts/modernizr-2.5.3.js"></script>

</head>
<body>
    

<div>
    <h2>test 1</h2>
    <input type="hidden" value="value" />
    <input type="text" />
    <input type="password" value="value" />
    False
    True
    <input type="text" value="value" />
    <input type="text" />
</div>
<div>
    <h2>test 2</h2>
    <" />
    <input type="hidden" value="True" />
    <input type="text" value="False" />
    <input type="password" value="True" />
    False
    <input type="text" value="True" />
    <input type="text" value="False" />
</div>

    <script src="/Scripts/jquery-1.7.1.js"></script>

    
</body>
</html>
I forgot to mention, in my second test I add an error to the html, after doing that Razor outputs the correct values.

I originally submitted this under the old project page: http://aspnet.codeplex.com/workitem/10320
but I realized it probably belongs here.
Closed Jun 5, 2013 at 9:59 PM by yishaigalatzer
This is a result of conditional attributes, and is indeed a breaking change between Razor V1 & Razor V2.

The workaround mentioned (using true.ToString() or making the model return a string rather than a straight bool is they way to go.

comments

craigtp wrote Feb 15, 2013 at 6:51 PM

This issue can be reproduced even easier.
  • Create a new MVC 4 web application using the "empty" template.
  • Add a Home controller and leave the default code that it puts in there (an Index method that simply returns View() ).
  • Create the "Index" view, leaving in the template code, but adding the following underneath:
<p class="@true"></p>
<p class="@false"></p>
<p class="@true.ToString()"></p>
<p class="@false.ToString()"></p>
<p value="@true"></p>
<p value="@false"></p>
<p value="@true.ToString()"></p>
<p value="@false.ToString()"></p>
<p style="@true"></p>
<p style="@false"></p>
<p style="@true.ToString()"></p>
<p style="@false.ToString()"></p>
Run the application. It'll simply render the word "Index" on the webpage, but then "View Source" and examine the rendered <p> tags.
The output should be:
<p class="class"></p>
<p></p>
<p class="True"></p>
<p class="False"></p>
<p value="value"></p>
<p></p>
<p value="True"></p>
<p value="False"></p>
<p style="style"></p>
<p></p>
<p style="True"></p>
<p style="False"></p>
It seems that, in all cases:
  • If .ToString() is appended to the boolean, the output is as you'd expect, either a true or false depending upon the boolean's value.
  • If the boolean has no ToString() and evaluates to true, Razor outputs the attribute name for the attribute value.
  • If the boolean has no ToString() and evaluates to false, Razor assumes "no value" and the conditional attribute mechanism kicks in and does not render either the attribute or the value.

craigtp wrote Feb 16, 2013 at 12:44 PM

I knew I'd read this somewhere, and I recently rediscovered Andrew Nurses' blog post on this feature:

http://vibrantcode.com/blog/2012/4/10/whats-new-in-razor-v2.html/

Seems that what Razor is doing is correct in that it's functioning as intended (i.e. if a boolean evaluates to true, the attribute name is rendered again as the attribute value). This makes perfect sense if you're rendering a checkbox and need to set it's checked value:
<input type=”checkbox” checked=”@isChecked”>
And I'm also aware that the Razor parser will ignore attributes that have the "data-" prefix, however, the rendering of the attributes name as it's value sill makes no sense for other attributes that might realistically need to contain the value of "true" or "false".

Sl0vi wrote Feb 27, 2013 at 3:03 PM

That makes sense, but I really don't like that the value attribute on input tags is treated like any other attribute on any other tag.

vdeepaksingh wrote Jan 20, 2014 at 10:02 AM

Found an interesting bug in razor parser. It not only ignores attributes that have the "data-"prefix, but it ignores all the attributes coming after those 'prefixed' attributes for a control. Assume that I have a div control/tag and the attributes are specified like this:

<div id="abc"
   forcedSearch = "true"
  data-enabled = "true" >
</div>

Then this gets rendered as:

<div id ="abc"
forcedSearch ="forcedSearch"
data-enabled ="true" >
</div>

But, If change the order of forcedSearch and data-enabled like this:
<div id="abc"
  data-enabled = "true"
   forcedSearch = "true" >
</div>

then the rendered html would be:

<div id="abc"
  data-enabled = "true"
   forcedSearch = "true" >
</div>

We can see the difference here. In first html, value of attribute "forcedSearch" was "forcedSearch", but in second html, it remains "true".

Developers, Please let me know whether it is a known issue?

Thanks!

P.S. : I got my code working by changing the order of attributes.