2

How should I write this so that Razor does not escape all the bits and bobs:

Helper class (ironically not that helpful)

public static class TableHeaderSortingHelpers
{
    public static string SortTableClickEvent(this HtmlHelper html, string url, string column)
    {
        string sortingPropertiesObject;
        sortingPropertiesObject = "var properties = new James.prototype.Table.SortingProperties();";
        sortingPropertiesObject += "properties.url = '" + url + "';";
        sortingPropertiesObject += "properties.colName = '" + column + "';";
        sortingPropertiesObject += "onclick = 'James.Table.SortByColumn(properties, this);'";

        return sortingPropertiesObject ;
    }
}

Razor view

<table class="table table-striped">
    <tr>
        <th width="100%" @Html.SortTableClickEvent(@Request.Path, "Name");>
            Name
        </th>

After compiling it looks like this:

<th width="100%" this);&#39;;="" &#39;name&#39;;onclick="'James.Table.SortByColumn(properties," =="" james.prototype.table.sortingproperties();properties.url="'/Site/List';properties.colName" properties="new" var="">
                Name
            </th>

EDIT //////////////////////

If I try to return an MVCHtmlString I get the following:

public static class TableHeaderSortingHelpers
{
    public static MvcHtmlString SortTableClickEvent(this HtmlHelper html, string url, string column)
    {
        string sortingPropertiesObject;
        sortingPropertiesObject = "var properties = new James.prototype.Table.SortingProperties();";
        sortingPropertiesObject += "properties.url = '" + url.ToString() + "';";
        sortingPropertiesObject += "properties.colName = '" + column + "';";
        sortingPropertiesObject += "onclick = 'James.Table.SortByColumn(properties, this);'";

        MvcHtmlString returnString = new MvcHtmlString(sortingPropertiesObject);

        return returnString;
    }
}

Output

<th width="100%" ;="" ;onclick="James.Table.SortByColumn(properties, this);" ;properties.colname="Name" james.prototype.table.sortingproperties();properties.url="/Site/List" properties="new" var="">
                Name
            </th>
Jimmyt1988
  • 20,466
  • 41
  • 133
  • 233
  • 2
    Can you post an example of your expected output? The reason I'm asking is because `var properties = ...` is going to end up directly in your `th` tag. – John H Jan 06 '14 at 12:56

2 Answers2

4

Try to return MvcHtmlString or HtmlString which should prevent the escape mechanism of razor

public static IHtmlString SortTableClickEvent(this HtmlHelper html, string url, string column)
{
    string sortingPropertiesObject;
    sortingPropertiesObject = "var properties = new James.prototype.Table.SortingProperties();";
    sortingPropertiesObject += "properties.url = '" + url + "';";
    sortingPropertiesObject += "properties.colName = '" + column + "';";
    sortingPropertiesObject += "onclick = 'James.Table.SortByColumn(properties, this);'";

    return new HtmlString(sortingPropertiesObject);
}

Update:

maybe instead of trying to instantiate a properties object (which will not work inline if you do not put everything in one line). Just use a normal json object and call your method. Helper could look like this for example:

public static IHtmlString SortTableClickEvent(this HtmlHelper html, string url, string column)
{
    string sortingPropertiesObject = string.Format(
        "onclick = \"James.Table.SortByColumn({{ url:'{0}', column:'{1}' }}, this);\""
        , url, column);

    return new HtmlString(sortingPropertiesObject);
}

Or if you want your custom properties object in javascript, just put everything in one line, as I said and escape everything correctly so that the onclick method is well formatted and doesn't break your html markup...

MichaC
  • 13,104
  • 2
  • 44
  • 56
  • Can you check out my OP again, I added a bit. Your example gave compile error: Error 1 Cannot implicitly convert type 'string' to 'System.Web.HtmlString' – Jimmyt1988 Jan 06 '14 at 12:26
  • This is another question, please remove your edit, mark this one as answered and add another question. Apart from that. You are trying to put everything into the inline onclick handle. This is very bad practice anyways and I wouldn't do that at all – MichaC Jan 06 '14 at 12:33
  • It's not a different question brah... Your suggestion unfortunately does not work... Also what I have done is not bad practice. I have literally declared a new properties to put into the one class I am calling onclick. I need a separate properties object for each call.. considering it's for table headers. – Jimmyt1988 Jan 06 '14 at 12:40
  • the code from my last edit works just fine. MvcHtmlString is derived from HtmlString. If you get compiler errors, maybe you are mixing System.Web.Mvc and System.Web.WebPages.Html? The question was why does your string get escaped. The answer was you are returning a string and not HtmlString. So yeah your new/updated question is a new question. – MichaC Jan 06 '14 at 12:50
  • Although this works fine, I'd rather use the interface `IHtmlString` as return type and `HtmlString` as implementation. Also see [this question](http://stackoverflow.com/questions/3382860/htmlstring-vs-mvchtmlstring) – Henk Mollema Jan 06 '14 at 13:04
1

I agree with MichaC that it's bad practice what you are trying to do. I propose this, where you keep the logic inside the view.

The html:

<th width="100%" class="sort-table" data-column="Name">
    Name
</th>

And the JavaScript, this must be inside the view.

<script type="text/javascript">
$(function() {
    $('.sort-table').click(function () {            
        // Get the value from the data-column attribute.
        var column = $(this).data('column');

        // Create object and set properties.
        var properties = new James.prototype.Table.SortingProperties();
        properties.url = '@Request.Path';
        properties.colName = column;

        // Sort the table.
        James.Table.SortByColumn(properties, this);
    });
});
</script>

However, I'm not sure that the click event can be bound to a <th> element.

Henk Mollema
  • 44,194
  • 12
  • 93
  • 104