简体   繁体   中英

Asp.net MVC Loading Parent View from the actionlink of PartialView using Ajax not working

I have a situation where I need to call ParentView from its partial view. Like I have list of ToDos in Partial view where Ajax actionlink is used to edit the data in parent by passing its id. The same is working without using Ajax as it is manipulating url by putting querystring. But we would like to have internal call with Ajax which is not firing.

The code we are using is like that:

<li>@Ajax.ActionLink(@item.ToDoTitle, "Index", new { tdid = @item.ToDoId }, new AjaxOptions { UpdateTargetId = "saved", InsertionMode = InsertionMode.Replace, HttpMethod="POST" })</li>

and controller is like that:

public ActionResult Index(int tdid =0)
    {
        if (tdid !=0)
        {
            ToDo t = new ToDo();
            t.ToDoTitle = "Ramlal";
            t.ToDoDesc = "Shyamlal";
            t.ToDoId = tdid;
            return Json(t);
        }
        else
        {
            return View();
        }
    }

We have tried the same with returning a view but nothing have happened, so we have tried to use Json as it returning model.

Correct me if I am wrong?

FYI, this is the parent view:

@model myTask.Models.ToDo
@{
    ViewBag.Title = "My Task";
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>

@using (Ajax.BeginForm("Save", new AjaxOptions() { InsertionMode = InsertionMode.Replace, UpdateTargetId = "MyTaskList" }))
{
    @Html.AntiForgeryToken()
    <div class="MyTask">
        @Html.HiddenFor(t => t.ToDoId)
        <div class="row">
            <div class="col-lg-12">
                @Html.LabelFor(t => t.ToDoTitle)<br />
                @Html.TextBoxFor(t => t.ToDoTitle)
            </div>
            <div class="col-lg-12">
                @Html.LabelFor(t => t.ToDoDesc)<br />
                @Html.TextAreaFor(t => t.ToDoDesc)
            </div>
        </div>
        <script>
            $( "#ToDoTitle" ).blur( function() {
                $.ajax({
                    url: "Save",
                    type: "POST",
                data: $("#form0").serialize(),
                dataType: "json"
                }).done(function (model) {
                $("#ToDoId").val(model.ToDoId);
                $("#ToDoTitle").val(model.ToDoTitle);
                $("#ToDoDesc").val(model.ToDoDesc);
            });
            });

            $("#ToDoDesc").blur(function () {
                if ($("#ToDoId").val() > 0) {
                    $.ajax({
                        url: "Save",
                        type: "POST",
                        data: $("#form0").serialize(),
                        dataType: "json"
                    }).done(function (model) {
                        $("#ToDoId").val(model.ToDoId);
                        $("#ToDoTitle").val(model.ToDoTitle);
                        $("#ToDoDesc").val(model.ToDoDesc);
                    });
                }});
        </script>
    </div>
    <div class="ObjectList" id="MyTaskList">
        @Html.Action("TodoList")
    </div>
    <div class="clearfix"></div>
}

This is partial view which is being called using @Html.Action("TodoList")

@using System.Linq
@model myTask.Models.ToDoList
@{
    ViewBag.Title = "Index";
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<div class="row">
    @if (Model.ToDos.Count > 0)
    {
        <ul>
            @foreach (var item in Model.ToDos)
            {
                @*<li>@Html.ActionLink(@item.ToDoTitle, "Index", new { tdid = @item.ToDoId })</li>*@
                <li>@Ajax.ActionLink(@item.ToDoTitle, "/Index", new { tdid = @item.ToDoId }, new AjaxOptions { UpdateTargetId = "MyTask", InsertionMode = InsertionMode.Replace, HttpMethod = "POST" })</li>
            }
        </ul>
    }
</div>

Controller:

using myTask.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;

namespace myTask.Controllers
{
    public class TasktdController : Controller
    {
        // GET: Tasktd
        public ActionResult Index(int tdid =0)
        {
            if (tdid !=0)
            {
                ToDo t = new ToDo();
                t.ToDoTitle = "Ramlal";
                t.ToDoDesc = "Shyamlal";
                t.ToDoId = tdid;
                return PartialView(t);
            }
            else
            {
                return View();
            }
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Save(ToDo td)
        {
            var errors = ModelState.Values.SelectMany(v => v.Errors);
            ModelState.Remove("ToDoId");
            if (ModelState.IsValid)
            {
                var t = await td.Save(td);
                return Json(td);
            }
            return Json("Oops! Error Occured");
        }
        [ChildActionOnly]
        public PartialViewResult TodoList()
        {
            ToDoList tdl = new ToDoList();
            List <ToDo> tds= new List<ToDo>();
            ToDo t = new ToDo();
            t.ToDoId = 1;
            t.ToDoTitle = "XXX";
            tds.Add(t);
            tdl.ToDos = tds;
            return PartialView(tdl);
        }
    }
}

There a number of problems with your code. First your submitting the form using .ajax() - and the form does not even have a submit button anyway! Replace

@using (Ajax.BeginForm("Save", new AjaxOptions() { ... })
{
  ....
}

with

<form id="form">
  .... // add controls for properties
  <button id="save" type="button">Save</button>
</form>

and remove the scripts for $( "#ToDoTitle" ).blur() and $("#ToDoDesc").blur() and replace with

<script>
  var form = $('#form');
  var saveUrl = '@Url.Action("Save")';
  $.post(saveUrl, form.serialize(), function(data) {
    if(data) {
      // save successful - give the user some feedback
    }
  }).fail(function (result) {
    // Oops and error occurred - give the user some feedback
  });
  .... // add script for editing here (see below0
</script>

Your current scripts result in poor performance and are the result of a bad UI design. The user should decide when to save (ie by clicking a button), not you. Consider what happens if the user edits the title and tabs to the description then realizes that all was correct and nothing needed to be changed afterall (you code has already altered the data in the database and the user would not even know it)

Note the script should be immediately before the closing </body> tag (not inline). And the Save() method should return Json(true) if the objects was successfully saved.

To handle clicking the 'links', change the partial to (note the @if block it not required)

<ul>
  @foreach (var item in Model.ToDos)
  {
    <li>
      <span>@item.ToDoTitle</span>
      <button class="edit" type="button" data-id="@item.@item.ToDoId">Edit</button>
    </li>
  }
</ul>

And if you want the button to look like a link, then use css to style it

Then add another script in the main view

var editUrl = '@Url.Action("Get")';
$('.edit').click(function() {
  var id = $(this).data('id');
  var title = $(this).prev('span').text();
  $.getJSON(editUrl, { id: id, function(data) {
    // Populate form fields
    $('#ToDoId').val(id);
    $('#ToDoTitle').val(title);
    $('#ToDoDesc').val(data);
  });
});

And the controller method would be

public JsonResult Get(int id)
{
  // Look up the Description based on the id, for example
  string description = db.ToDo.Where(x => x.ToDoId == id).Select(x => x.ToDoDesc);
  return Json(description, JsonRequestBehavior.AllowGet);
}

Note, you already have the ID and Title properties in the view so its only necessary to return the Description (and I suggest you change your property names as suggested here - ie ID , Title and Description )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM