4

How can I add additional values to the InsertionMode enum?

I have tried

public class MyAjaxOptions : AjaxOptions
{
    public new InsertionModeCustom InsertionMode;
}

public enum InsertionModeCustom
{
    Replace = 0,
    InsertBefore = 1,
    InsertAfter = 2,
    ReplaceWith = 3,
    AppendTo = 4,
    PrependTo = 5
}

However, once the MyAjaxOptions is passed to an Ajax.ActionLink, MyAjaxOptions is cast back to System.Web.Mvc.Ajax.AjaxOptions so InsertionMode is not enum InsertionModeCustom but rather back to enum InsertionMode. The value becomes Replace (being the first value) because AppendTo and PrependTo no longer exist.

Valamas
  • 24,169
  • 25
  • 107
  • 177
  • I am afraid this might not be doable, because, not only you can't inherit from an Enum, but also other consumer classes such as `AjaxOptions`, `AjaxExtensions` (class that contains `Ajax.BeginForm()`) don't provide any override-able methods for others to override the default behavior. The source code is here by the way: https://github.com/aspnet/AspNetWebStack/tree/master/src/System.Web.Mvc/Ajax. I would like to challenge myself so I would take a look at it when I have time. Trying to figure out if I can come out anything else other than coping the existing codes. – David Liang Sep 08 '20 at 17:46
  • @Valamas what are you trying to do with `AppendTo` and `PrependTo` and how are they different from `InsertBefore` or `InsertAfter`? – vvvv4d Sep 08 '20 at 20:27
  • If you add `new` in front of a property or a field that doesn't override the one from the base class.`New`keyword there will overload and if someone cast something like `AjaxOption x = new MyAjaxOption` then `x.InsertionMode` will not be the one from your `MyAjaxOption`. – Cristian-Ștefăniță Scăueru Sep 09 '20 at 20:59
  • @vvvv4d Inserting or appending rows to a table – Valamas Sep 09 '20 at 21:14
  • @Cristian-ȘtefănițăScăueru Yes, I stated that – Valamas Sep 09 '20 at 21:15
  • You are probably looking for Enum Inheritance which has an answer in this post you might find useful: https://stackoverflow.com/questions/757684/enum-inheritance Sadly, Enum Inheritance is not possible, although the post provides a workaround with classes. That may or may not meet your use case. – vvg Sep 10 '20 at 14:53

2 Answers2

1

Against lacking the feature you are asking about (Inheritance of enums), which was pointed at in comments (here and here), perhaps a different approach can provide a workaround for your intended task.

As you state here (this is perhaps better placed in the OP), you mean to Insert or append rows to a table. For that sake, you may find a (partial?) workaround in the two-step method shown in

  1. Ajax.ActionLink insert after header in a table?

  2. How To add a row to table by ajax actionlink

0

As you have discovered it is not possible to extend the InsertionMode enum that ActionLink accepts.

That said, if you re-examine the core problem you're trying to solve that approach shouldn't be necessary.

The only thing Ajax.ActionLink does is generate an HTML anchor tag. You can create the same tag by substituting the invalid call (using your AppendTo option):

@Ajax.ActionLink("Append To Table", "GetRowData",
    new AjaxOptions
    {
        HttpMethod = "GET",
        InsertionMode = InsertionMode.AppendTo,
        UpdateTargetId = "myAjaxData",
    });

with:

@Html.ActionLink("Append To Table", "GetRowData", null, 
    new { 
            data_ajax = "true", 
            data_ajax_method = "GET", 
            data_ajax_mode = "appendTo", 
            data_ajax_update = "myAjaxData"
    }
);

This produces the same anchor tag as if you had been able to extend the enums.

As far as the solution goes that is only half the story, because you'd also need to modify the Unobtrusive JavaScript library to handle your new AppendTo and PrependTo options (not recommended).

Unobtrusive JavaScript adds click handlers to each anchor tags with data-ajax="true" attributes. If it detects an invalid InsertionMode it will default to InsertionMode.Replace.

One solution, if you particularly want to use Ajax.ActionLink, is use its standard functionality to update a hidden div, and then call a JS function to append/prepend the data to the table:

Index.cshtml:

@Ajax.ActionLink("Prepend To Table", "GetRowData",
             new AjaxOptions
             {
                 HttpMethod = "GET",
                 InsertionMode = InsertionMode.Replace,
                 UpdateTargetId = "myAjaxData",
                 OnComplete = "prependToTable('#tableOfDoubles', '#myAjaxData');"
             });

@Ajax.ActionLink("Append To Table", "GetRowData",
             new AjaxOptions
             {
                 HttpMethod = "GET",
                 InsertionMode = InsertionMode.Replace,
                 UpdateTargetId = "myAjaxData",
                 OnComplete = "appendToTable('#tableOfDoubles', '#myAjaxData');"
             });

<div id="myAjaxData" style="display:none;">
  data will end up here
</div>

<table style="border-spacing: 7px; border-collapse: separate;">
  <thead>
    <tr>
      <th>Number</th>
      <th>Number doubled</th>
    </tr>
  </thead>
  <tbody id="tableOfDoubles">
    <tr>
      <td>1</td>
      <td>2</td>
    </tr>
  </tbody>
</table>

JavaScript:

<script type="text/javascript">
  function prependToTable(tableId, dataId) {
    try {
      var newData = JSON.parse($(dataId).text());
      var row = ("<tr><td>" + newData.Number + "</td><td>" + newData.Doubled + "</td></tr>");
      $(tableId).prepend(row);
    } catch (ex) {
      console.error(ex);
    }
  }

  function appendToTable(tableId, dataId) {
    try {
      var newData = JSON.parse($(dataId).text());
      var row = ("<tr><td>" + newData.Number + "</td><td>" + newData.Doubled + "</td></tr>");
      $(tableId).append(row);
    } catch (ex) {
      console.error(ex);
    }
  }
</script>

Controller:

using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace AjaxActionLink.Models
{
    public class MyData
    {
        public int Number { get; set; }
        public int Doubled => Number * 2;
    }
}

namespace AjaxActionLink.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public string GetRowData()
        {
            JavaScriptSerializer js = new JavaScriptSerializer();

            // generate demo data
            int someNumber = (int)(Session["tableRowValue"] ?? 1);
            Session["tableRowValue"] = ++someNumber;
            // end of data generation

            var newData = new MyData { Number = someNumber };
            return js.Serialize(newData);
        }
    }
}

Having said all that, personally I would just add a onclick handler to a tag and make an ajax call using jQuery (something like this), using my functions above to add the response to the table.

K Scandrett
  • 16,390
  • 4
  • 40
  • 65