eric kulcyk
eric kulcyk

Reputation: 171

How can I make an asp.net mvc checkbox trigger an action?

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?

Upvotes: 7

Views: 17436

Answers (4)

Gary Mason
Gary Mason

Reputation: 9

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>

Upvotes: 0

JB06
JB06

Reputation: 1931

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>
}

Upvotes: 7

Reza Aghaei
Reza Aghaei

Reputation: 125302

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.

Upvotes: 3

Kunal B.
Kunal B.

Reputation: 563

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

Upvotes: 0

Related Questions