I have a Kendo Grid set up as follows. The url is for the code snippet below, which is an ASP.NET Web Api. When I use "Add new record" on the grid and the press Update, the Post method is called as expected, and the musics parameter exists as expected, however, it is empty. The stringify method has nothing to stringify, in other words. Why is the binding not happening?
dataSource = new kendo.data.DataSource({
transport: {
...
create: {
url: "/api/mywebapi/",
type: "POST"
},
parameterMap: function (data, operation) {
if (operation !== "read" && data.models) {
return { models: kendo.stringify(data.models) };
}
return { models: kendo.stringify(data) };
}
...
The Web Api method:
public HttpResponseMessage Post(IEnumerable<MusicVM> musics)
{
...
}
I should say that in debug I can see that operation is "create" and that data.models does indeed have the new item I entered in the grid.
Finally, after years of struggle, I stumbled upon something that works. I changed parameterMap to this:
parameterMap: function (data, operation) {
if (operation !== "read" && data.models) {
var items = {};
$.each(data.models, function (index, item) {
for (var key in item) {
items["[" + index + "]" + "." + key] = item[key];
}
});
return items;
}
Why this was so difficult, I have no idea, but thanks to Burke Holland for this.
http://blogs.telerik.com/kendoui/posts/11-11-07/batch_crud_operations_with_kendo_ui_datasource
Instead of using
public HttpResponseMessage Post(IEnumerable<MusicVM> musics)
{
...
}
Use
public JsonResult Post(string models)
{
//Deserialize string to object
IList<MusicVM> musics= new JavaScriptSerializer().Deserialize<IList<MusicVM>>(models);
return Json(musics)
}
Note that parameterMap: function() send data in serialize format with name models so you should use models as parameter name in your action
you may refer to this post as well
Related
I am new in MVC. I have a DropDown in index view and i want to show entire table basis on selected item from dropdown. I fire ajax on onChange function of dropdown using jQuery.
$(document).ready(function () {
$("#ddlUser").change(function () {
$("#ddl2").empty();
$.ajax({
type: "POST",
url: '#Url.Action("getState")',
dataType: "json",
data: { id: $("#ddlUser").val() },
success: function (city) {
},
error: function (ex) {
alert('failed to retrieve' + ex);
}
})
});
return false;
});
and i get data from database using this code
public JsonResult getState(int id)
{
MvcDemo9Feb.Models.ModelData MD = new Models.ModelData(); //MD is object of model and dt is DataTable type property
MD.dt = obDB.getCity(id);//obDB is class and getCity is method of it that return datatable
return Json(MD);
}
here i don't know how to bind data of model object MD to table on view. Please suggest something
I have the below ajax call code from jquery.
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: oAxn.ds,
data: JSON.stringify(oAxn.p(graphsDrpDwn)),
beforeSend: function () {
$(".errorMsg").hide();
YC.toggleLoadingImg(tabId, false);
},
success: function (graphData) {
if (typeof oAxn.s === "function") {
if (graphData.reportData.ErrorMsg !== "Success") {
$(".errorMsg").show().html(graphData.reportData.ErrorMsg);
$("#tabs").hide();
YC.toggleLoadingImg(tabId, true);
} else {
//Inorder to avoid flicker, we hide in style sheet on page load.
$("#tabs").show();
$(".lblDrp").show();
$("#MainDiv").show();
YC.showRangeSel();
YC.toggleLoadingImg(tabId, true);
oAxn.s(graphData, grphOneID, grphTwoID);
}
}
},
error: function (err) {
YC.toggleLoadingImg(tabId, true);
}
});
The method that gets the parameters JSON.stringify(oAxn.p(graphsDrpDwn)) is:
getDealerParams: function (graphsDrpDwn) {
/// <summary>We gather the parameters required for dealer tab</summary>
/// <param name="graphsDrpDwn" type="string">Holds the dropdown list id</param>
return {
//We get these from hidden inputs, since they won't be available
// in the query string for framed in reports
shopId: $(".txtShopId").val(),
siteId: $("." + graphsDrpDwn).find(":selected").attr("data-field"),
dealerId: $("." + graphsDrpDwn).find(":selected").val(),
frmDate: $(".tsFrom").val(),
toDate: $(".tsTo").val()
};
},
All parameters are getting values except frmDate, toDate.
I can see the values in client side but when passed to controller two are always null.
And it is only happening in my system, it is working fine in my colleagues machine.
can some body advise what could be wrong here?
This is not the ideal solution but it worked for us on couple projects. In Global.asax we put the following code:
protected void Application_BeginRequest(Object sender, EventArgs e)
{
var newCulture = (CultureInfo)Thread.CurrentThread.CurrentCulture.Clone();
newCulture.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
newCulture.DateTimeFormat.DateSeparator = "/";
Thread.CurrentThread.CurrentCulture = newCulture;
}
Of course you need to change the date format to the one you need.
Adding the below attributes in aspx file for page directive worked for me.
UICulture="es" Culture="es-US"
Below an Ajax call wrapped inside a jQuery autocomplete source function. checking the return value in Fiddler and also in Chrome's Network console, I can see that the data is being returned to the view and in the correct format.
However, the normal list of items that occur when the user starts typing do not appear. You can type as fast/slow for as little/long as you want and nothing will appear.
I've set a breakpoint in the controller method (this is an ASP MVC site) just to make sure that part of the program was functioning properly, and it fires every time.
I'm only a few weeks new to jQuery so any help would be greatly appreciated. Thanks!
$(function () {
$('#DRMCompanyId').autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("compSearch", "AgentTransmission")',
type: 'GET',
dataType: 'json',
data: request,
success: function (data) {
alert(data);
response($.map(function (value, key) {
alert(value);
return {
label: value,
value: key
};
}));
}
});
},
minLength: 1
});
});
EDIT
I added a couple alerts to the code. The alert(data) will fire but the alert(value) will not.
Here is a copy of the returned json from the Chrome's debugging console
And here is the controller method that returns the key/value pair in the form of a Dictionary object.
XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
nsmgr.AddNamespace("m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
nsmgr.AddNamespace("d", "http://schemas.microsoft.com/ado/2007/08/dataservices");
Dictionary<string, string> companies = new Dictionary<string, string>();
foreach (XmlNode childNode in parentNode)
{
if (!String.IsNullOrWhiteSpace(childNode["content"].InnerText))
{
try
{
string name = childNode["title"].InnerText;
string id = childNode["content"].InnerText.Substring(0, 6);
companies.Add(id, name);
}
catch (Exception ex)
{
}
}
}
return Json(companies, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
results = ex.InnerException.ToString();
}
return Json(results, JsonRequestBehavior.AllowGet);
The $.map function expects an array/object to enumerate on, as first argument. ref jQuery.map.
try changing
$.map(function (value, key) {
to
$.map(data, function (value, key) {
Regards.
The jQuery documentation: http://api.jquery.com/jQuery.map/ says that the $.map function expects two parameters; the first being an array. I think that you need to use the $.each method instead.
I also believe that in this context, response is a callback function that you are supposed to invoke with the data from AJAX as the parameter, as in response(data).
Shooting from the hip here, I think that your success handler should look about like this:
success: function (data) {
var x, array = [];
for(x in data) {
array.push({
label: data[x].value,
value: data[x].key
};
}
response(data);
}
I am building a MVC3 web application and I am using knockoutjs. There are two views in the application. SetUpNewCompany and ManageAccount. To Set up a new company the user first enters the account number and clicks search. If the account number already exists the user can click on a button to go to the ManageAccount view. In the SetUpNewCompanyController I redirect using the RedirectToAction method. However, when the Index2 action in ManageAccount is executed the view is not displayed. If I type in the complete URL the view is displayed.
SetUpNewCompanyController.cs
[HttpPost]
public RedirectToRouteResult RedirectToManageAccount(string accountNumber)
{
return RedirectToAction("Index2", new RouteValueDictionary(new {controller=
"ManageAccount", companyId = "7e96b930-a786-44dd-8576-052ce608e38f" }));
}
This above is called by the function below when a button is clicked
self.redirectToManageAccount = function () {
var accountNumber = "7e96b930-a786-44dd-8576-052ce608e38f";
$.ajax({
type: "POST",
url: "/SetUpNewCompany/RedirectToManageAccount",
data: { accountNumber: accountNumber },
success: function (data) {
},
error: function () {
}
});
}
ManageAccountController.cs
public ActionResult Index2(String companyId)
{
var viewModel = new Models.Index();
List<String> compList = new List<String>();
compList.Add("MyCompany");
List<String> usersList = new List<String>();
usersList.Add("User1");
viewModel.Users = usersList;
viewModel.Companies = compList;
viewModel.CompanyId = companyId;
viewModel.Role = "Role1";
return View("ManageAccount",viewModel);
}
The URL that is generated is
http://localhost:53897/ManageAccount/Index2?companyId=7e96b930-a786-44dd-8576-
052ce608e38f
The console window in Firebug shows
GET http://localhost:53897/ManageAccount/Index2?companyId=7e96b930-a786-44dd-8576-
052ce608e38f 200 OK and the spinner keeps spinng
Also, how do I get the URL below instead of the one with querystring
http://localhost:53897/ManageAccount/Index2/7e96b930-a786-44dd-8576-052ce608e38f
Since you use AJAX to call the RedirectToManageAccount action method, you are responsible for handling its response yourself and as your success handler function is empty, you are effectively ignoring whatever arrives as a response.
If you want to force a redirect from within the AJAX response handler, I suggest
Modifying your action method as follows
[HttpPost]
public ActionResult RedirectToManageAccount(string accountNumber)
{
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index2", "ManageAccount", new { companyId = "7e96b930-a786-44dd-8576-052ce608e38f" });
return Json(new { Url = redirectUrl });
}
Updating your AJAX call in this way
self.redirectToManageAccount = function () {
var accountNumber = "7e96b930-a786-44dd-8576-052ce608e38f";
$.ajax({ type: "POST",
url: "/SetUpNewCompany/RedirectToManageAccount",
data: { accountNumber: accountNumber },
dataType: 'json',
success: function (response) {
window.location.href = response.Url;
},
error: function () {
}
});
}
As for your second question:
Also, how do I get the URL below instead of the one with querystring
http://localhost:53897/ManageAccount/Index2/7e96b930-a786-44dd-8576-052ce608e38f
You just have to define an appropriate route entry for this URL in your RegisterRoutes() function:
routes.MapRoute(null,
"ManageAccount/Index2/{companyId}",
new { controller = "ManageAccount",
action = "Index2" }
);
EDIT: As your AJAX call only serves to call an action method which causes a redirect, you can simplify it in a following way, provided you in this point (on the client side) know the companyId already:
self.redirectToManageAccount = function () {
var companyId = "12345";
window.location.href = '#(Html.ActionUri("Index2", "ManageAccount"))?companyId=' + companyId;
}
where I used this extension method
public static string ActionUri(this HtmlHelper html, string action, string controller)
{
return new UrlHelper(html.ViewContext.RequestContext).Action(action, controller);
}
I have an MVC application that I'm using various JsonResult endpoints to populate the javascript ViewModel.
I have been using several jQuery Ajax requests to populate the model, but I'd like as much of the inital model to be passed to the view on the server.
The ViewModel has 3-5 pieces (depending on where the user is in the application):
Basic page links, these don't change very often and could be the exact same throughout the entire user's session
User notifications.
User data.
(optional) Viewable data
(optional) misc data
I'm currently using this code to load the first three pieces:
$(document).ready(function () {
ko.applyBindings(viewModel);
#Html.Raw(ViewBag.Script)
// Piece 1. Almost always the same thing
postJSON('#Url.Action("HomeViewModelJson", "Home")', function (data) {
if (data == null)
return;
for (var i in data.Tabs) {
viewModel.tabs.push({ name: data.Tabs[i] });
}
for (var i in data.Buttons) {
viewModel.metroButtons.push({ name: data.MetroButtons[i] });
}
for (var i in data.Ribbons) {
viewModel.ribbons.push(data.Ribbons[i]);
}
ApplyButtonThemes();
});
});
// Piece 2. Changes constantly. OK as is
postJSON('#Url.Action("GetNotifications", "NotificationAsync")', function (nots) {
viewModel.notifications.removeAll();
ko.utils.arrayForEach(nots, function (item) {
item.readNotification = function () {
hub.markNotificationAsRead(this.Id);
return true;
};
viewModel.notifications.push(item);
});
});
// Piece 3. Changes but should also be loaded at startup
postJSON('#Url.Action("GetUser", "UserAsync")', function (user) {
viewModel.user(koifyObject(user));
});
postJSON = function(url, data, callback) {
if($.isFunction(data)) {
callback = data;
data = {};
}
$.ajax({
'type': 'POST',
'url': url,
'contentType': 'application/json',
'data': ko.toJSON(data),
'dataType': 'json',
'success': callback
});
};
I tried doing something like this, but I'm finding that by using the #Html.Action("HomeViewModelJson", "Home") is causing the HTTP headers to get changed and the whole page is sent as if it were JSON
(function (data) {
if (data == null)
return;
for (var i in data.Tabs) {
viewModel.tabs.push({ name: data.Tabs[i] });
}
for (var i in data.MetroButtons) {
viewModel.metroButtons.push({ name: data.MetroButtons[i] });
}
for (var i in data.Ribbons) {
viewModel.ribbons.push(data.Ribbons[i]);
}
ApplyMetroButtonThemes();
})('#Html.Action("HomeViewModelJson", "Home")');
What I'd like to do is use the existing JsonResult endpoints to get Json data into my ViewModel on the server side, before the page is sent to the user.
Are there any options that will allow me to do that w/o rewriting my controllers?
When rendering the main view you are using a view model, right? In this view model simply populate the properties that you don't want to be fetched with AJAX before returning the view:
public ActionResult Index()
{
MyViewModel model = ...
model.Prop1 = ...
model.Prop2 = ...
return View(model);
}
for example if you have the following action that is used for the AJAX requests:
public JsonResult GetProp1()
{
Property1ViewModel model = ...
return Json(model, JsonRequestBehavior.AllowGet);
}
you could use it from the main action to populate individual properties:
model.Prop1 = (Property1ViewModel)GetProp1().Data;
model.Prop2 = (Property2ViewModel)GetProp2().Data;
and then inside the corresponding view you could use the Json.Encode method to serialize the entire model into a JSON string:
#model MyViewModel
<script type="text/javascript">
var model = #Html.Raw(Json.Encode(Model));
// You could use model.Prop1 and model.Prop2 here
</script>
or you could also serialize individual properties if you don't need all of them:
#model MyViewModel
<script type="text/javascript">
var prop1 = #Html.Raw(Json.Encode(Model.Prop1));
</script>