This is a migrated thread and some comments may be shown as answers.

post viewmodel with jquery for grid

11 Answers 318 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Stephen
Top achievements
Rank 1
Stephen asked on 11 Feb 2014, 07:20 PM
Hello,

I have a grid on a partial view which is loaded through jquery/json.  The delete is handled through the grid with jquery/json.  Previously I was posting the partial view to do the add and then reload the grid.  Now I need a button on the partial view that does the add for the grid but does not submit the whole partial view.  I have it working by passing the data through variables but I would like to pass the view model instead.  Is there a way to do this through jquery?

Here is my current code:

Partial View:
@model PASS.ViewModels.Proposals.RequiredViewModel
 
@using (Ajax.BeginForm("_Required", "Proposals", new AjaxOptions { UpdateTargetId = "requiredReturnMsg", HttpMethod = "Post", OnComplete="onDataUpdated()" }))
{
  
@Html.HiddenFor(model => model.Proposal_ID, Model.Proposal_ID)
 
<div class="editor-container">
 
    <div class="proposal-info">
        <p>User Facility:  @Html.DisplayFor(model => model.User_Facility_ID)</p>
        <p>Proposal Type: @Html.DisplayFor(model => model.Proposal_Type)</p>
        <p>Proposal ID: @Html.DisplayFor(model => model.Proposal_ID)</p>
    </div>
    <br class="clear" />
 
    <div class="editor-label">
        @Html.Label("Primary Field of Research:")
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.Research_Field_ID,  new SelectList(Model.ResearchFields, "Value""Text"), "(Select One)")
        @Html.ValidationMessageFor(model => model.Research_Field_ID)
    </div>   
    <br class="clear" />
    <br />
    <br />
    <div class="editor-label">
        @Html.Label("Funding Source")
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.Funding_Source_ID,  new SelectList(Model.FundingSources, "Value""Text"), "(Select One)")
        @Html.ValidationMessageFor(model => model.Funding_Source_ID)
        <input type="button" id="AddFundingSource" value="Add Funding Source" />
    </div>   
    <br class="clear" />
    <div class="editor-label">
        @Html.Label("Specify (only if requested)")
    </div>
    <div class="editor-field">
        @Html.TextBoxFor(model => model.Funding_Specify, new { style = "width: 350px;" })
        @Html.ValidationMessageFor(model => model.Funding_Specify)
    </div>
    <br class="clear" />
    <br />
    <br />
    <p><input type="submit" value="Save" /></p>
    <br />
    <br />
    @(Html.Kendo().Grid<PASS.ViewModels.Proposals.FundingSourcesViewModel>()
        .Name("gridFundingSources")
        .Columns(columns =>
        {
            columns.Bound(o => o.FundingSourceDescription).Title("Funding Source");
            columns.Bound(o => o.Funding_Specify).Title("Specifics");
            columns.Command(command => { command.Destroy(); }).Width(90);
        })
        .Sortable()
        .DataSource(dataSource => dataSource
            .Ajax()
            .Model(model => model.Id(o => o.ID))
            .Read(read => read.Action("GetFundingSources", "Proposals", new {proposalID = Model.Proposal_ID}))
            .Destroy(destroy => destroy.Action("DeleteFundingSource", "Proposals"))
        )
    )
    <br />
    <br />
 
    <div id="requiredReturnMsg"></div>
 
</div>
     
}
 
<script type="text/javascript">
$(document).ready(function () {
    $("#AddFundingSource").click(function () {
        var proposalID = $("#Proposal_ID").val();
        var fundingSourceID = $("#Funding_Source_ID").val();
        var fundingSpecify = $("#Funding_Specify").val();
        $.post('/Proposals/AddFundingSource', { proposalID: proposalID, fundingSourceID: fundingSourceID, fundingSpecify: fundingSpecify }, function (data) {
            onDataUpdated();
        });
    });
});
function onDataUpdated() {
    var grid = $("#gridFundingSources").data("kendoGrid");
    grid.dataSource.read();
}
</script>


Controller:
[HttpPost]
public ActionResult AddFundingSource([DataSourceRequest]DataSourceRequest request, FundingSourcesViewModel vm, int proposalID, int fundingSourceID, string fundingSpecify)
{
    using (var context = new PASSEntities())
    {
        var model = new Proposal_Funding_Sources()
        {
            Proposal_ID = proposalID,
            Funding_Source_ID = fundingSourceID,
            Funding_Specify = fundingSpecify
        };
        context.Proposal_Funding_Sources.Add(model);
        context.SaveChanges();
    }
    return Json(new[] { vm }.ToDataSourceResult(request));
}

I would like to do this just by passing the view model but I don't know if this is possible.

Thanks,

Steve




11 Answers, 1 is accepted

Sort by
0
Alexander Popov
Telerik team
answered on 13 Feb 2014, 04:49 PM
Hello Stephen,

I am not sure I understand you question correctly, however I would recommend the following approach:
  1. Set up the Create method of the Grid's DataSource 
  2. Once the Add button is clicked use the insert method to add a new row to the Grid
  3. Call the sync method to send the new row to the AddFundingSource action method

For example: 
.DataSource(dataSource => dataSource
    .Ajax()
    .Model(model => model.Id(o => o.ID))
    .Read(read => read.Action("GetFundingSources", "Proposals", new {proposalID = Model.Proposal_ID}))
    .Create(read => read.Action("AddFundingSource", "Proposals"))
    .Destroy(destroy => destroy.Action("DeleteFundingSource", "Proposals"))
)
 
 
$("#AddFundingSource").click(function () {
    var proposalID = $("#Proposal_ID").val();
    var fundingSourceID = $("#Funding_Source_ID").val();
    var fundingSpecify = $("#Funding_Specify").val();
    var grid = $("#gridFundingSources").data("kendoGrid");
    grid.dataSource.insert({Proposal_ID: proposalID, Funding_Source_ID: fundingSourceID, Funding_Specify:, fundingSpecify}, 0);
    grid.dataSource.sync();
});
 
 
public ActionResult AddFundingSource([DataSourceRequest]DataSourceRequest request, FundingSourcesViewModel vm)

This should properly populate the DataSourceRequest and bind the new row data to the FundingSourcesViewModel vm parameter.

Regards,
Alexander Popov
Telerik
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
0
Stephen
Top achievements
Rank 1
answered on 18 Mar 2014, 02:31 PM
Hello,

Thank you for the response.  This is doing what I was hoping for with one exception...

It does add the data to the view model and when it posts to the method it does add it successfully, but when the button is clicked it adds an empty row to the grid but the data itself doesn't show in that row until I refresh the page. 

I tried adding: grid.dataSource.read(); after your grid.dataSource.sync(); call but that makes it worse because then it doesn't even show the new empty row added to the grid.

Am I missing something?
0
Alexander Popov
Telerik team
answered on 20 Mar 2014, 09:47 AM
Hi Stephen,

This behavior is a bit strange and I am not sure what is causing it. Basically the Grid immediately reflects all changes in its DataSource, so adding a new item through the insert method should create a new row in the Grid and how the respective value. Could you please check this screencast and let me know how this differs from your case?

Regards,
Alexander Popov
Telerik
 
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
 
0
Stephen
Top achievements
Rank 1
answered on 20 Mar 2014, 01:42 PM
Ok I see what the difference is and I tested to verify.

Only one of the columns I am displaying in my grid is a parameter that is passed to the insert method.  My grid is displaying the description that is related to the ID that is added.  Here is the column that actually displays the Funding Source that was added:

columns.Bound(o => o.FundingSourceDescription).Title("Funding Source");

I also show the Funding Specify:

columns.Bound(o => o.Funding_Specify).Title("Specifics");

If I do a specify then the row shows at least that column filled but the other doesn't fill because I believe it needs my Get method in order to fill it.  That FundingSourceDescription is not one of the parameters sent.  The ID is sent and in my Get method when I build my viewmodel I define that description.

public ActionResult GetFundingSources(int proposalID, [DataSourceRequest]DataSourceRequest request)
{
    using (var context = new PASSEntities())
    {
        var vm = (from a in context.Proposal_Funding_Sources
                  join b in context.Funding_Sources on a.Funding_Source_ID equals b.ID
                  where a.Proposal_ID == proposalID
                  select new FundingSourcesViewModel()
                  {
                     ID = a.ID,
                     Proposal_ID = a.Proposal_ID,
                     Funding_Source_ID = a.Funding_Source_ID,
                     Funding_Specify = a.Funding_Specify,
                     FundingSourceDescription = b.Description
                  });
         
        DataSourceResult result = vm.ToDataSourceResult(request);
        return Json(result, JsonRequestBehavior.AllowGet);
    }
}

So it seems like I need to also call the get method again in order to populate that column.  Is this possible? 
0
Alexander Popov
Telerik team
answered on 24 Mar 2014, 10:44 AM
Hi Stephen,

Yes, you could make an ajax request and pass the ID to the GetFundingSources method. Once the request's success event is triggered use the response data as parameters for the insert method.

Regards,
Alexander Popov
Telerik
 
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
 
0
Stephen
Top achievements
Rank 1
answered on 25 Mar 2014, 01:59 PM
Hi,

Ok so now I'm not quite sure I understand.  Don't I need the insert method in order to do the insert with the viewmodel?  That was what your original answer was providing.  So wouldn't I be doing the GetFundingSources after the insert? Not doing the insert on success of the GetFundingSources?

I tried calling GetFundingSources after the insert but that doesn't seem to work.  Does the grid.dataSource.insert have a success event?

Thanks,

Steve
0
Alexander Popov
Telerik team
answered on 27 Mar 2014, 10:42 AM
Hello again Steve,

I apologize for the misleading response. Please, let me know if my understanding is correct:
  1. Users are populating some of the item's fields
  2. The item is then sent to the server, where the rest of the fields are populated and the item is saved
  3. The server populated fields are not displayed on the Grid until the page is refreshed, even if the dataSource read method is called

I would also ask you to provide a runnable sample project so we can reproduce the issue locally and advise you further. If that is not possible, sharing all related views, models and controllers would also be of help.

Regards,
Alexander Popov
Telerik
 
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
 
0
Stephen
Top achievements
Rank 1
answered on 01 Apr 2014, 03:10 PM
Hi Alexander,

That is not exactly right.  All of the necessary data is populated through the form fields.  It is sent to the server and then onComplete of the ajax form, I call the grid.dataSource.read.  The reason I do this is because the grid is showing a nice description instead of the id that the form field populates.  I can't put together a sample project at the moment but here is all of the code.

Partialview:
@model PASS.ViewModels.Proposals.RequiredViewModel
 
@using (Ajax.BeginForm("_Required", "Proposals", new AjaxOptions { UpdateTargetId = "requiredReturnMsg", HttpMethod = "Post", OnComplete="onDataUpdated()" }))
{
  
@Html.HiddenFor(model => model.Proposal_ID, Model.Proposal_ID)
@Html.HiddenFor(model => model.Proposal_Research_Field_ID, Model.Proposal_Research_Field_ID)
 
<div class="editor-container">
 
    <div class="editor-label">
        @Html.Label("Please choose the most appropriate Proposal Review Panel:")
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.PRP_ID,  new SelectList(Model.PRPs, "Value",  "Text"), "(Select One)")
        @Html.ValidationMessageFor(model => model.PRP_ID)
    </div>   
    <br class="clear" />
    <br />   
    <div class="editor-label">
        @Html.Label("Primary Field of Research:")
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.Research_Field_ID,  new SelectList(Model.ResearchFields, "Value",  "Text"), "(Select One)")
        @Html.ValidationMessageFor(model => model.Research_Field_ID)
    </div>   
    <br class="clear" />
    <br />
    <div class="editor-label">
        @Html.Label("Funding Source:")
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.Funding_Source_ID,  new SelectList(Model.FundingSources, "Value",  "Text"), "(Select One)")
        @Html.ValidationMessageFor(model => model.Funding_Source_ID)
        <input type="button" id="AddFundingSource" value="Add Funding Source" />
    </div>   
    <br class="clear" />
    <br />
    <div class="other-specify">
        <div class="editor-label">
            @Html.Label("Specify")
        </div>
        <div class="editor-field">
            @Html.TextBoxFor(model => model.Funding_Specify, new { style = "width: 350px;" })
            @Html.ValidationMessageFor(model => model.Funding_Specify)
        </div>
        <br class="clear" />
        <br />
    </div>
    <br />
    <br />
    @(Html.Kendo().Grid<PASS.ViewModels.Proposals.FundingSourcesViewModel>()
        .Name("gridFundingSources")
        .Columns(columns =>
        {
            columns.Bound(o => o.FundingSourceDescription).Title("Funding Source");
            columns.Bound(o => o.Funding_Specify).Title("Specifics");
            columns.Command(command => { command.Destroy(); }).Width(90);
        })
        .Sortable()
        .DataSource(dataSource => dataSource
            .Ajax()
            .Model(model => model.Id(o => o.ID))
            .Read(read => read.Action("GetFundingSources", "Proposals", new {proposalID = Model.Proposal_ID}))
            .Create(create => create.Action("AddFundingSource", "Proposals"))
            .Destroy(destroy => destroy.Action("DeleteFundingSource", "Proposals"))
        )
    )
    <br />
    <br />
    <p><input type="submit" value="Save" /></p>
    <br />
    <br />
 
    <div id="requiredReturnMsg"></div>
 
</div>
     
}
 
<script type="text/javascript">
$(document).ready(function () {
    $("#Funding_Source_ID").change(function () {
        var fundingSourceID = $("#Funding_Source_ID").val();
        $.post('/Proposals/GetFundingSourceSpecify', { fundingSourceID: fundingSourceID }, function (data) {
            if (data == 'Y') {
                $(".other-specify").css('display', 'block');
            }
        });
    });
 
    $("#AddFundingSource").click(function () {
        var proposalID = $("#Proposal_ID").val();
        var fundingSourceID = $("#Funding_Source_ID").val();
        var fundingSpecify = $("#Funding_Specify").val();
        /*
        var grid = $("#gridFundingSources").data("kendoGrid");
        grid.dataSource.insert({Proposal_ID: proposalID, Funding_Source_ID: fundingSourceID, Funding_Specify: fundingSpecify}, 0);
        grid.dataSource.sync();
        */
         
        $.post('/Proposals/AddFundingSource', { proposalID: proposalID, fundingSourceID: fundingSourceID, fundingSpecify: fundingSpecify }, function (data) {
            onDataUpdated();
        });
         
    });
});
function onDataUpdated() {
    var grid = $("#gridFundingSources").data("kendoGrid");
    grid.dataSource.read();
}
</script>

The commented out code above is what you provided. I am trying to replace my post call sending the variables with sending the ViewModel instead.

Controller:
[HttpPost]
public ActionResult AddFundingSource([DataSourceRequest]DataSourceRequest request, FundingSourcesViewModel vm, int proposalID, int fundingSourceID, string fundingSpecify)
{
    using (var context = new PASSEntities())
    {
        var model = new Proposal_Funding_Sources()
        {
            Proposal_ID = proposalID,
            Funding_Source_ID = fundingSourceID,
            Funding_Specify = fundingSpecify
        };
        context.Proposal_Funding_Sources.Add(model);
        context.SaveChanges();
    }
    return Json(new[] { vm }.ToDataSourceResult(request));
}
  
/*
[HttpPost]
public ActionResult AddFundingSource([DataSourceRequest]DataSourceRequest request, FundingSourcesViewModel vm)
{
    using (var context = new PASSEntities())
    {
        var model = new Proposal_Funding_Sources()
        {
            Proposal_ID = vm.Proposal_ID,
            Funding_Source_ID = vm.Funding_Source_ID,
            Funding_Specify = vm.Funding_Specify
        };
        context.Proposal_Funding_Sources.Add(model);
        context.SaveChanges();
    }
    return Json(new[] { vm }.ToDataSourceResult(request));
}
*/
 
public ActionResult GetFundingSources(int proposalID, [DataSourceRequest]DataSourceRequest request)
{
    using (var context = new PASSEntities())
    {
        var vm = (from a in context.Proposal_Funding_Sources
                  join b in context.Funding_Sources on a.Funding_Source_ID equals b.ID
                  where a.Proposal_ID == proposalID
                  select new FundingSourcesViewModel()
                  {
                     ID = a.ID,
                     Proposal_ID = a.Proposal_ID,
                     Funding_Source_ID = a.Funding_Source_ID,
                     Funding_Specify = a.Funding_Specify,
                     FundingSourceDescription = b.Description
                  });
         
        DataSourceResult result = vm.ToDataSourceResult(request);
        return Json(result, JsonRequestBehavior.AllowGet);
    }
}
 
public JsonResult GetFundingSourceSpecify(int fundingSourceID)
{
    var context = new PASSEntities();
 
    string specify = (from a in context.Funding_Sources where a.ID == fundingSourceID select a.Require_Specific).SingleOrDefault();
 
    return Json(specify);
}
 
[HttpPost]
public ActionResult DeleteFundingSource([DataSourceRequest]DataSourceRequest request, FundingSourcesViewModel vm)
{
    using (var context = new PASSEntities())
    {
        var model = new Proposal_Funding_Sources()
        {
            ID = vm.ID,
            Proposal_ID = vm.Proposal_ID,
            Funding_Source_ID = vm.Funding_Source_ID,
            Funding_Specify = vm.Funding_Specify
        };
        context.Proposal_Funding_Sources.Attach(model);
        context.Proposal_Funding_Sources.Remove(model);
        context.SaveChanges();
    }
    return Json(new[] { vm }.ToDataSourceResult(request));
}

ViewModel:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
namespace PASS.ViewModels.Proposals
{
    public class FundingSourcesViewModel
    {
        public int ID { get; set; }
        public int Proposal_ID { get; set; }
        public int Funding_Source_ID { get; set; }
        public string Funding_Specify { get; set; }
 
        public string FundingSourceDescription { get; set; }
    }
}














0
Alexander Popov
Telerik team
answered on 03 Apr 2014, 12:57 PM
Hi Stephen,

You can send an object that has the same properties as the FundingSourcesViewModel, so that the AddFundingSource method would bind its "vm" parameter to it. For example: 
$.post('/Proposals/AddFundingSource', {
        vm: {
            Proposal_ID: proposalID,
            Funding_Source_ID: fundingSourceID,
            Funding_Specify: fundingSpecify
        }
    },
    function (data) {
        onDataUpdated();
});
[HttpPost]
public ActionResult AddFundingSource([DataSourceRequest]DataSourceRequest request, FundingSourcesViewModel vm)
{
    ...
}


Regards,
Alexander Popov
Telerik
 
Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!
 
0
Stephen
Top achievements
Rank 1
answered on 03 Apr 2014, 02:57 PM
I didn't realize that was possible...I am a bit of a novice with jquery.  Though it didn't work until I specified the datatype as json.

$.post('/Proposals/AddFundingSource', {
        vm: {
            Proposal_ID: proposalID,
            Funding_Source_ID: fundingSourceID,
            Funding_Specify: fundingSpecify
        }
    },
    function (data) {
        onDataUpdated();
    }, "json");
0
Stephen
Top achievements
Rank 1
answered on 03 Apr 2014, 03:41 PM
I also just realized I didn't even need to create the collection.  If I just post it like this:
$.post('/Proposals/AddFundingSource', { Proposal_ID: proposalID, Funding_Source_ID: fundingSourceID, Funding_Specify: fundingSpecify }, function (data) {
    onDataUpdated();
});

it knows that these are properties of the ViewModel (since the names match I guess) and it just puts it in to the ViewModel.



Tags
Grid
Asked by
Stephen
Top achievements
Rank 1
Answers by
Alexander Popov
Telerik team
Stephen
Top achievements
Rank 1
Share this question
or