Paolo B Paolo B - 2 months ago 8
Ajax Question

How do I serialise item in Model for a jQuery Ajax POST using ActionLink

I am using the following example model:

public class MyModel
{
public int Id { get; set; }

public string Text { get; set; }

public string Description { get; set; }

public bool? Accepted { get; set; }
}


Using this to show buttons if value for Accepted is null, otherwise show their choice:

@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.Text)
</td>
<td>
@Html.DisplayFor(modelItem => item.Description)
</td>
<td class="accepted">
@{
if (item.Accepted == null)
{
@Html.ActionLink("Accept", "Edit", "MyModels", new { id = item.Id, Accepted = true, Text = item.Text, Description = item.Description },
new { @class = "btn btn-success btn-xs" })
@Html.ActionLink("Decline", "Edit", "MyModels", new { id = item.Id, Accepted = false, Text = item.Text, Description = item.Description },
new { @class = "btn btn-danger btn-xs" })
}
else if (item.Accepted == true)
{
<span>Accepted</span>
}
else if (item.Accepted == false)
{
<span>Declined</span>
}
}
</td>


Its working - But how could I handle this if there were 50 or 100 properties - I couldn't put them on the Actionlink?

My model in view is
IEnumerable<MyModel>
and I need to access the releveant
item.Id
in the foreach loop and serialise but I am not sure how? for example as below but model is a json Array of all Objects, cannot access
item.id
out of scope (in the
<script>
tag at botton of View), how do i just get the single item:

$('#MyTable td.accepted a').click(function() {
var model = @Html.Raw(Json.Encode(Model)); // this is an array of Objects (Model is IEnumberable<MyModel>)
$.ajax({
url: this.href,
type: 'POST',
contentType: 'json',
data: model[item.id], //here I just want to get 1 object
success: function(result) {
window.location.reload(true);
}
});
return false;
});


So I am sure there is a better way to accomplish this, e.g. sent the single item in the Model as one in the POST - I searched but could find no relevant question - please enlighten me.

P.S. sorry for my English, hope you can follow.

Edit: MVC Controller POST action:

[HttpPost]
public ActionResult Edit([Bind(Include = "Id,Text,Accepted,Description")] MyModel myModel)
{
if (ModelState.IsValid)
{
_db.Entry(myModel).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(myModel);
}


enter image description here

Answer

Simple - use some forms and hidden inputs:

<td class="accepted">
    @{
        if (item.Accepted == null)
        {
            <form action="@Url.Action("Edit", "MyModels")" method="post" class="action-form">
                <input type="hidden" name="Id" value="@item.Id" />
                <input type="hidden" name="Accepted" value="true" />
                <button type="submit" class = "btn btn-success btn-xs">Edit</button>
            </form>

            <form action="@Url.Action("Edit", "MyModels")" method="post" class="action-form">
                <input type="hidden" name="Id" value="@item.Id" />
                <input type="hidden" name="Accepted" value="false" />
                <button type="submit" class = "btn btn-danger btn-xs">Decline</button>
            </form>
        }
        else if (item.Accepted == true)
        {
            <span>Accepted</span>
        }
        else if (item.Accepted == false)
        {
            <span>Declined</span>
        }
    }
</td>

Adjust your jQuery code a bit:

$('#MyTable form.action-form').on('submit', function(e) {

    e.preventDefault();

    var model = $(this).serialize();
    var url = $(this).attr('action');

    $.post(url, model)
        .done(function(result, status, jqxhr){
            window.location.reload(true);
        });
});

It looks as though you're using your data models as view models. I wouldn't recommend that, but you can make it work as-is by doing this:

[HttpPost]
public ActionResult Edit(MyModel model)
{
    if (ModelState.IsValid)
    {
        var entry = _db.MyModels.SingleOrDefault(m => m.ID == model.ID);
        if(entry != null)
        {
            entry.Accepted = model.Accepted;
            _db.SaveChanges();

            return RedirectToAction("Index");
        }
    }

    return View(myModel);
}

This way, you're only updating the properties that actually need to be changed.