7

I would like to update the database when someone checked a box that represents a bit field on the row. I have been going off of this question: Ajax.ActionLink(...) with checkbox Here is my code in the cshtml file:

@foreach (var item in Model) {
<tr>
    <td>
        @Html.DisplayFor(modelItem => item.Macro_Name)
    </td>
    <td>
        @Html.CheckBoxFor(modelItem => item.Claimed, new { id = item.Macro_Name, data_url = Url.Action("ToggleClaim", "MacroStatus")})
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Date_Claimed)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Username)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Finished)
    </td>
    <td>
        @Html.DisplayFor(modelItem => item.Date_Completed)
    </td>
    <td>
        @Html.ActionLink("Edit", "Edit", new { id=item.Macro_Name }) |
        @Html.ActionLink("Details", "Details", new { id = item.Macro_Name }) |
        @Html.ActionLink("Delete", "Delete", new { id = item.Macro_Name })
    </td>
</tr>
}

In the MacroStatusController class I have the following action:

    public ActionResult ToggleClaim(string id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }

        MacroStatus macroStatus = db.MacroStatus1.Find(id);
        if (macroStatus == null)
        {
            return HttpNotFound();
        }

        if (ModelState.IsValid)
        {
            macroStatus.Date_Claimed = DateTime.Now;
            db.Entry(macroStatus).State = EntityState.Modified;
            db.SaveChanges();
        }

        return new HttpStatusCodeResult(HttpStatusCode.OK);
    }

However, ToggleClaim isn't running when I check or uncheck the box. There are no compile errors. This is my first try with asp.net mvc, what am I doing wrong?

Community
  • 1
  • 1
eric kulcyk
  • 161
  • 1
  • 1
  • 3
  • The `data-url` attribute only contains some url now. There needs to be some piece of Javascript that uses it. – haim770 Oct 14 '15 at 18:59
  • 1
    There are a ton of ways to approach this, but you need something to do an AJAX call to a server endpoint (probably a Web API method, since you're using ASP.net MVC) when you check that box. The "quick and dirty" answer is to use a jQuery selector for you checkbox and register a function using $([selector]).change(function(){}); You could also bind the checkbox to a kendo viewmodel function, or any number of other approaches. – bopapa_1979 Oct 14 '15 at 19:07
  • You could look here, too: http://stackoverflow.com/questions/1784412/asp-net-mvc-simulating-autopostback-for-simple-checkbox – bopapa_1979 Oct 14 '15 at 19:09
  • @EricBurcham The key point is sending an ajax request when checkbox changed. – Reza Aghaei Oct 14 '15 at 19:22
  • @RezaAghaei - I thought that was clear in my comment, but you are absolutely correct. – bopapa_1979 Oct 14 '15 at 19:26
  • @EricBurcham Yes it's clear in your comment. I think having an answer is more useful than leaving comment. unfortunately I didn't read your comment but as I see now your comment is good as answer :) I edited the answer and mentioned you:) Hope you find it helpful or let me know if you prefer to post your own answer:) – Reza Aghaei Oct 14 '15 at 19:33

4 Answers4

7

You will need ajax for this. First, add a class to the checkboxes so you will have a hook to attach your click event.

@Html.CheckBoxFor(modelItem => item.Claimed, new { id = item.Macro_Name, @class = "toggle" data_url = Url.Action("ToggleClaim", "MacroStatus")})

Now add your javascript.

@section scripts {
    <script>
        $(function() {
            $('.toggle').change(function() {
                var self = $(this);
                var url = self.data('url');
                var id = self.attr('id');
                var value = self.prop('checked');

                $.ajax({
                    url: url,
                    data: { id: id },
                    type: 'POST',
                    success: function(response) {
                        alert(response);
                    }
                });
            });
        });
    </script>
}
JB06
  • 1,881
  • 14
  • 28
  • , class = "toggle" is giving me a syntax error here. Is that a valid keyword here? – eric kulcyk Oct 14 '15 at 19:26
  • Sorry, class is a reserved word, escape it with @ - `@class = "toggle"` – JB06 Oct 14 '15 at 19:43
  • hi how to *update the row upon Ajax success/fail*. For e.g. if `Status` was a col in the row. And if Approved/Rejected was a radio button with some notes, so if I want to -- toggle the color of the row, and update the value of status in the row. – Transformer Dec 28 '17 at 06:06
3

The key point is sending an ajax request when checkbox changed.

As mentioned in comments by Eric, You can trigger that action using many different ways. for example, put this script in your codes:

<script>
    $(function () {
        $('#Claimed').change(function () {
            $.ajax({
                url: '/ToggleClaim/MacroStatus/@item.Macro_Name',
                cache: false,
                method: 'GET',
                success: function (data) { alert('success'); },
                error: function () { alert('error'); }
            });
        });
    });
</script> 

And correct checkbox code this way:

<td>
    @Html.CheckBoxFor(modelItem => item.Claimed)
</td>

The above code, triggers the action each time you check or uncheck the checkbox, you can simply check if the checkbox is checked and then send ajax request.

Community
  • 1
  • 1
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
0

The reason is that when checkbox is unchecked & form is submitted; no form field related to checkbox is submitted. You either have to use JavaScript to add hidden variable as described in Post the checkboxes that are unchecked, or make a Ajax hit when checkbox is checked. jQuery Ajax checkbox state

Community
  • 1
  • 1
Kunal B.
  • 543
  • 6
  • 22
0

This can be done without script using fontawesome and a anchor with a standard controller.

Add a link to the css file in your layout page.

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.1/css/all.css"           
integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" 
crossorigin="anonymous">

In your view or display template add an anchor

<a asp-controller="MacroStatus" asp-action="ToggleClaim" asp-route- 
id="item.Macro_Name">
@if (item.Claimed)
{
    <span class="fas fa-toggle-on fa-2x"></span>
}
else
{
    <span class="fas fa-toggle-off fa-2x"></span>
}
</a>

It looks like a checkbox and is clickable and is also great if you have multiple instances in one view, for example if you are using a display template for an array of objects.

The above can be made very clean and re-usable by using a component for the toggle on/off part.

<vc:toggle-on-off toggle="@item.Claimed"></vc:toggle-on-off>

Then it would look something like:

<a asp-controller="MacroStatus" asp-action="ToggleClaim" asp-route- 
id="item.Macro_Name">
    <vc:toggle-on-off toggle="@item.Claimed"></vc:toggle-on-off>
</a>