Here's my issue. I'm making an ajax request to obtain an object from a controller. The object (or something) is being brought back, but I don't know how to access the attributes of that object being brought back. The object is of type "Address" and thus has attributes like Address.Address1, Address.City, etc. Here is my code: After a button is clicked,
function showEditAddress(addressid) {
$.get("/Website/Accommodation/AddressGet",
{ guid: addressid.toString() },
function(data) {
//Get values from variable 'data' such as described above
//and append to form 'dialog'
$("#dialog").dialog({
// autoOpen: false,
show: {
effect: "explode",
duration: 250
},
hide: {
effect: "explode",
duration: 250
},
buttons: {
"Save": {
text: "Save",
class: "",
click: function () {
//save form
$(this).dialog("close");
}
},
"Cancel": {
text: "Cancel",
class: "",
click: function () {
$(this).dialog("close");
}
}
},
modal: true
});
});
}
Controller action:
public Address AddressGet(string guid)
{
Guid g = new Guid(guid);
return _iCoreRepository.Addresses.Where(p => p.AddressID == g).SingleOrDefault();
}
Any help will be greatly appreciated!!! Thank you!!!
Jose is quite simple. You already answer the question. To get the value of the properties of Address you only need put a dot in front of data and type de property name. like this:
//(....)
function(data) {
//Get values from variable 'data' such as described above
//and append to form 'dialog'
//show address id.
alert(data.AddressID);
Remember that javascript is case sensitive, so you need use upper case to A and ID in AddressID like you did in C#.
And in controller you need replace the last line to something like this:
var address = _iCoreRepository.Addresses.Where(p => p.AddressID == g).SingleOrDefault();
return Json(address, JsonRequestBehavior.AllowGet);
the method must be return JsonResult. The method Json serialize the object, in this case address, in a json format before response the data to the client.
If you need the Json method accepts IEnumerables to, like List<> or Array. In javascript your data object will be a lenght property and will acess each element by using indexer like:
data[0].AddressID.
Instead of returning just your Address object you can try returning a JsonResult.
public ActionResult AddressGet(string guid)
{
Guid g = new Guid(guid);
var address = _iCoreRepository.Addresses.Where(p => p.AddressID == g).SingleOrDefault();
return Json(address, JsonRequestBehavior.AllowGet);
}
Then in your jquery, the returned data is your address object and you can access the fields as they appear in your C# class:
function showEditAddress(addressid) {
$.get("/Website/Accommodation/AddressGet",
{ guid: addressid.toString() },
function(data) {
//Get values from variable 'data' such as described above
//and append to form 'dialog'
//Access it like: data.Address1, data.City etc...
});
}
}
Related
How would I get the value of card_number to pass to the controller?
Every time I submit the form I get NULL in the form variable
View:
#Html.EditorFor(model => model.card_number, new { htmlAttributes = new { #id = "card_number" } })
<script>
var frm = $('#formFilter');
function OnFormSubmit() {
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: function (frm) {
frm.card_number = $('#card_number').val();
},
success: function (data) {
$("#dataResult").html(data);
$('#dataTable').DataTable({
"dom": 'lifrtp'
});
}
});
}
</script>
controller:
private List<testtest> GetListChanges(Report changeControl)
{
...logic here....
return returnListhere;
}
The data property of the $.ajax method options should be an object or string which represents your data. With your current code you are setting a function to that.
var d = {
card_number: "1234",
someOtherPropertyNameOfReport: "Hello"
};
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: JSON.stringify(d),
contentType:"application/json",
success: function (data) {
console.log(data);
}
});
Now jquery will send the request with Content-Type request header value set to application/json and request data (the stringified version of your JavaScript object) in the request body and model binder will be able to properly read and map it to your view model, assuming the structure of the view model matches with your JavaScript object structure.
As suggested in the comment, try to use serialize() method. It is simply and you do not need to manually build the object.
Also your controller action method should be public
The way my code works currently is when a button is pressed variables are passed and Jquery unhides a modal window and makes an AJAX call to get the [HttpGet] portion of my Controller Action. This loads a form in the modal window. The modal has a save and cancel button, when the save button is pressed the form is submitted with ajaxSubmit. On successful save something is saved to the database, then a url is created and passed back to jquery and user is redirected with window.location.href.
What I'd like to have happen is when the save button is pressed the [HttpPost] part of controller action will make some logic choices, and if a certain condition is met within the action then return PartialView(model) is returned back to the modal window with an error message or pop up so that the user doesn't have to retype their information and understands why the save didn't go through and can edit quickly and try save again.
The Jquery:
var createNewClaimSetup = function () {
$(selectors.btnCreateNewClaim).live('click', function () {
var serialNumber = $(this).attr(attributes.serialNumber);
var spaRegistrationId = $(this).attr(attributes.spaRegistrationId);
var customerNumber = $(this).attr(attributes.customerNumber);
var customerStatementName = $(this).attr(attributes.customerStatementName);
$(selectors.serialNumberHidden).val(serialNumber);
$(selectors.spaRegistationIdHidden).val(spaRegistrationId);
$(selectors.customerNumberHidden).val(customerNumber);
$(selectors.customerStatementName).val(customerStatementName);
$(selectors.dialog).attr(attributes.title, 'Create New Claim');
$.ajax ({
url: inputs.warrantyClaimCreateUrl,
type: "GET",
data: {
serialNumber: serialNumber,
customerNumber: customerNumber
},
cache: false,
success: function (result) {
$(selectors.dialog).html(result.toString());
$(selectors.dialog).dialog ({
resizable: false,
height: 600,
width: 850,
modal: true,
buttons: {
'Save': function () {
// check to see if a value has been entered for problem description before submitting form
//
if(!$('#AddProblemModel_ProblemDesc').val().length==0 && (!$('#ClaimPrefix').val().length==0 || $('#chkManualClaimNum').is(':checked')))
$(selectors.createNewClaimForm).ajaxSubmit({
cache: false,
success: function (data) {
if (data.length == 0) {
location.reload();
$(selectors.dialog).dialog('close');
} else {
$(selectors.dialog).dialog('close');
window.location.href = data.redirectToUrl;
}
}
});
else{
return alert('You must select a prefix and enter a description for the problem before saving');
}
},
Cancel: function () {
$(this).dialog('close');
}
}
});
}
});
});
}
Controller Action GET (edited for brevity):
public virtual ActionResult WarrantyClaimCreateNew(string serialNumber, string customerNumber, string customerStatementName)
{
WarrantyClaimModel model = wcs.CreateNewClaimInfo(serialNumber, customerNumber, false);
ViewBag.InvalidPrefix = false;
ViewBag.DupeWaNum = false;
return View(model);
}
Controller Action POST (edited for brevity):
[HttpPost]
public virtual ActionResult WarrantyClaimCreateNew(WarrantyClaimCreateNewModel model)
{
if (ModelState.IsValid)
{
WaNumberDupeModel WAdupe = new WaNumberDupeModel(model.WarrantyClaimNumber);
// Rebuild WarrantyClaimModel object to pass back to view
WarrantyClaimModel model2 = wcs.CreateNewClaimInfo(model.SerialNumber, model.CustomerNumber, false);
// check if prefix is valid
if (WAdupe.DupeType == WaDupeType.InvalidPrefix)
{
ViewBag.InvalidPrefix = true;
return PartialView(model2);
//return Json(new { Url = Url.Action("WarrantyClaimCreateNew", model2) });
}
// check if wa number already exists
if (WAdupe.DupeExists)
{
ViewBag.DupeWaNum = true;
return PartialView(model2);
}
// create/save the new claim
if (wcs.CreateNewWarrantyClaim(model))
{
var redirectString = "WarrantyClaimDetail?warrantyClaimNumber=" + model.WarrantyClaimNumber;
if (Request.IsAjaxRequest())
{
return Json(new { redirectToUrl = redirectString }, JsonRequestBehavior.AllowGet);
}
return RedirectToAction(Actions.WarrantyClaimDetail(newClaimNumber));
}
return RedirectToAction(Actions.WarrantyClaimSaveFail());
}
else
{
return View(model);
}
}
Alerts In View If Conditions In Controller Action Met:
<%if (ViewBag.InvalidPrefix == true) { %>
alert("Please choose a valid prefix for your warranty claim number.");
<% } %>
<%if (ViewBag.DupeWaNum == true) { %>
alert("Warranty Claim Number already exists, please choose another manual WA number or try again.");
<% } %>
I haven't even been able to reload the view refreshed in the modal at all, let alone with changed to the bound model intact.
I know that the first part of the AJAX call (type: "GET") uses the URL to go into the controller action GET and gets back the return View(model) then converts it to HTML and sets the modal window HTML to it. I've been assuming that the ajaxSubmit goes back to the controller and gets the POST version of the action, and that the data part of success: function (data) should be the view return if condition is met and the built JSON URL to redirect to if it's not.
I've tried setting the modal html to data and making sure the controller invalid prefix condition is met, however the content in the modal window never seems to refresh. I'll also need to figure out how to logically tell in JQUERY if the controller returned a view or a URL through JSON but I don't think that will be hard to figure out.
I've read through a dozen or so mvc jquery ajax modal similar questions and they've helped but not
Thanks for any help shedding some light on how I might accomplish what a want here.
Sort of a partial answer to what I was looking for. I realize now my main stumbling block was to have my test alerts before building the modal window as "return alert(whatever)" which was obviously returning the alert and not running the rest of the code, dumb.
The solution I have working now is a pretty bad hack. I have it rebuild the modal and attach the POST view data to it. However this isn't looped so if you save and fail again I've set it to alert the user save failed again and to retry, then the modal closes and they can start again from scratch.
Tomorrow I'll see about turning this into a looping rather than nested structure.
New "working" JQuery code:
var createNewClaimSetup = function () {
$(selectors.btnCreateNewClaim).live('click', function () {
var serialNumber = $(this).attr(attributes.serialNumber);
var spaRegistrationId = $(this).attr(attributes.spaRegistrationId);
var customerNumber = $(this).attr(attributes.customerNumber);
var customerStatementName = $(this).attr(attributes.customerStatementName);
$(selectors.serialNumberHidden).val(serialNumber);
$(selectors.spaRegistationIdHidden).val(spaRegistrationId);
$(selectors.customerNumberHidden).val(customerNumber);
$(selectors.customerStatementName).val(customerStatementName);
$(selectors.dialog).attr(attributes.title, 'Create New Claim');
$.ajax ({
url: inputs.warrantyClaimCreateUrl,
type: "GET",
data: {
serialNumber: serialNumber,
customerNumber: customerNumber
},
cache: false,
success: function (result) {
$(selectors.dialog).html(result.toString());
$(selectors.dialog).dialog ({
resizable: false,
height: 600,
width: 850,
modal: true,
buttons: {
'Save': function () {
// check to see if a value has been entered for problem description before submitting form
//
if(!$('#AddProblemModel_ProblemDesc').val().length==0 && (!$('#ClaimPrefix').val().length==0 || $('#chkManualClaimNum').is(':checked')))
$(selectors.createNewClaimForm).ajaxSubmit({
cache: false,
success: function (data) {
if (data.length == 0) {
location.reload();
$(selectors.dialog).dialog('close');
} else if(data.redirectToUrl) {
$(selectors.dialog).dialog('close');
window.location.href = data.redirectToUrl;
} else {
$(selectors.dialog).html(data.toString());
$('#chkManualClaimNum').attr('checked','checked');
$('#manualClaimInfo').toggle();
$(selectors.dialog).dialog ({
resizable: false,
height: 600,
width: 850,
modal: true,
buttons: {
'Save': function () {
if(!$('#AddProblemModel_ProblemDesc').val().length==0 && (!$('#ClaimPrefix').val().length==0 || $('#chkManualClaimNum').is(':checked')))
$(selectors.createNewClaimForm).ajaxSubmit({
cache: false,
success: function (data) {
if (data.length == 0) {
location.reload();
$(selectors.dialog).dialog('close');
} else if(data.redirectToUrl) {
$(selectors.dialog).dialog('close');
window.location.href = data.redirectToUrl;
} else {
alert('Save failed again. Please start over.');
$(selectors.dialog).dialog('close');
}
}
});
},
Cancel: function () {
$(this).dialog('close');
}
}
});
}
}
});
else{
return alert('You must select a prefix and enter a description for the problem before saving');
}
},
Cancel: function () {
$(this).dialog('close');
}
}
});
}
});
});
}
This does at least show how to pass the POST view back to the modal window.
I am trying to create a modal that will tell the user their submission was successfully submitted. This works fairly well, but the only problem is I have to declare each of my properties and assign it a value, then in the Json method I have accept all those parameters then do something with them. Is there any way to do this with a ViewModel? Or any otherway that this can be done using a ViewModel?
controller:
public Json Send(string var1, string var2)
{
...
if(valid)
return new Json(true, JsonRequestBehavior.AllowGet);
else
return new Json(false, JsonRequestBehavior.AllowGet);
}
javascript:
function submitData() {
$.ajax({
url: "/Report/Send",
type: "POST",
dataType: "json",
data: { var1 = Model.var1, var2 = Model.var2... },
success: function (data) {
if(data) {
showDialog();
}
else {
$("#errorDiv").load('Report/Error/');
}
},
error: function (somefunction) { }
});
}
Yes, create a ViewModel POCO class:
var myJsonResult = new { result: true };
return Json(myJsonResult);
You can also use a strongly typed ViewModel and return that:
var myJsonResult = new CustomResult { result: true };
return Json(myJsonResult);
Then just check that property on the class in your success function:
success: function (data) {
if(data.result) {
showDialog();
}
else if(!data.result) {
$("#errorDiv").load('Report/Error/');
}
},
EDIT:
You might also want to look at jquery's .serialize() method:
data: $("#myForm").serialize()
This will be useful if you bind your ViewModel to form elements and need to post them back to the server.
I started using knockout.js and i really like it.
I use ASP.Net mvc , jQuery and knockout.js
My question is this:
lets say i have a management screen of a user, the user is my view model
inside the user i want an array of permissions
my user viewModel:
var userViewModelClass = function () {
var self = this;
ko.mapping.fromJS({
ID: "",
permissions: []
}, {}, self);
}
now.. if i do an ajax request to the server and get a JSON back i user the mapping plugin, and everything goes as expected
but... now i want my rendered permissions list to have an action like delete.
so i will need a permission object and then the array of permissions will be an array of permission objects. but how do i do that? how will the mapping plugin know that the object returned to him from the server in an array is actually on object like this one:
function permission() {
var self = this;
this.delete = function () {
};
ko.mapping.fromJS({
name: "",
level: ""
}, {}, self);
}
that's my first part of the question.
the second part:
lets say i got the model with an array of all permissions and they are all of this permission object. now i want each delete button in my view to be bind the the delete function inside the permission object.
using:
data-bind="click: delete"
what is the best implementation for a delete function? i thought about something like: makeing an ajax call to the server which will actually delete the permission from the user. then if the call succeeds remove the current permission from the observable array, then the view will update...
is that a good practice?
thanks!
First part. You need to use mapping options. In your userViewModelClass do this.
var userViewModelClass = function () {
var self = this;
ko.mapping.fromJS({
ID: "",
permissions: []
}, {
permissions: {
create: function(options) {
return new permission(options.data);
}
}
}, self);
}
And modify your permission object like so
function permission(config) {
var self = this;
this.delete = function () {
};
ko.mapping.fromJS($.extend({
name: "",
level: ""
}, config), {}, self);
}
Note I added the extend in so that your default structure will remain and be overwritten by incoming data.
Second part of your question. One possible way would be to pass a reference to the parent in your constructor. So the above mapping options would become
permissions: {
create: function(options) {
return new permission(options.data, self);
}
}
Then your delete could be something like.
this.delete = function () {
$.ajax(deleteurl, yourdata, function(result) {
// success
parent.permissions.remove(self);
}, function() {
// failure
display error message
}
};
EDIT
Alternate way as discussed in comments.
var userViewModelClass = function () {
var self = this;
ko.mapping.fromJS({
ID: "",
permissions: []
}, {
permissions: {
create: function(options) {
return new permission(options.data);
}
}
}, self);
this.delete = function(permission) {
self.permissions.remove(permission);
};
}
data-bind="click: $parent.delete"
Hope this helps.
In doing an auto-refresh using the following code, I assumed that when I do a post, the model will automatically sent to the controller:
$.ajax({
url: '<%=Url.Action("ModelPage")%>',
type: "POST",
//data: ??????
success: function(result) {
$("div#updatePane").html(result);
},
complete: function() {
$('form').onsubmit({ preventDefault: function() { } });
}
});
Every time there is a post, I need to increment the value attribute in the model:
public ActionResult Modelpage(MyModel model)
{
model.value = model.value + 1;
return PartialView("ModelPartialView", this.ViewData);
}
But the model is not passed to the controller when the page is posted with jQuery AJAX request. How can I send the model in the AJAX request?
The simple answer (in MVC 3 onwards, maybe even 2) is you don't have to do anything special.
As long as your JSON parameters match the model, MVC is smart enough to construct a new object from the parameters you give it. The parameters that aren't there are just defaulted.
For example, the Javascript:
var values =
{
"Name": "Chris",
"Color": "Green"
}
$.post("#Url.Action("Update")",values,function(data)
{
// do stuff;
});
The model:
public class UserModel
{
public string Name { get;set; }
public string Color { get;set; }
public IEnumerable<string> Contacts { get;set; }
}
The controller:
public ActionResult Update(UserModel model)
{
// do something with the model
return Json(new { success = true });
}
If you need to send the FULL model to the controller, you first need the model to be available to your javascript code.
In our app, we do this with an extension method:
public static class JsonExtensions
{
public static string ToJson(this Object obj)
{
return new JavaScriptSerializer().Serialize(obj);
}
}
On the view, we use it to render the model:
<script type="javascript">
var model = <%= Model.ToJson() %>
</script>
You can then pass the model variable into your $.ajax call.
I have an MVC page that submits JSON of selected values from a group of radio buttons.
I use:
var dataArray = $.makeArray($("input[type=radio]").serializeArray());
To make an array of their names and values. Then I convert it to JSON with:
var json = $.toJSON(dataArray)
and then post it with jQuery's ajax() to the MVC controller
$.ajax({
url: "/Rounding.aspx/Round/" + $("#OfferId").val(),
type: 'POST',
dataType: 'html',
data: json,
contentType: 'application/json; charset=utf-8',
beforeSend: doSubmitBeforeSend,
complete: doSubmitComplete,
success: doSubmitSuccess});
Which sends the data across as native JSON data.
You can then capture the response stream and de-serialize it into the native C#/VB.net object and manipulate it in your controller.
To automate this process in a lovely, low maintenance way, I advise reading this entry that spells out most of native, automatic JSON de-serialization quite well.
Match your JSON object to match your model and the linked process below should automatically deserialize the data into your controller. It's works wonderfully for me.
Article on MVC JSON deserialization
This can be done by building a javascript object to match your mvc model. The names of the javascript properties have to match exactly to the mvc model or else the autobind won't happen on the post. Once you have your model on the server side you can then manipulate it and store the data to the database.
I am achieving this either by a double click event on a grid row or click event on a button of some sort.
#model TestProject.Models.TestModel
<script>
function testButton_Click(){
var javaModel ={
ModelId: '#Model.TestId',
CreatedDate: '#Model.CreatedDate.ToShortDateString()',
TestDescription: '#Model.TestDescription',
//Here I am using a Kendo editor and I want to bind the text value to my javascript
//object. This may be different for you depending on what controls you use.
TestStatus: ($('#StatusTextBox'))[0].value,
TestType: '#Model.TestType'
}
//Now I did for some reason have some trouble passing the ENUM id of a Kendo ComboBox
//selected value. This puzzled me due to the conversion to Json object in the Ajax call.
//By parsing the Type to an int this worked.
javaModel.TestType = parseInt(javaModel.TestType);
$.ajax({
//This is where you want to post to.
url:'#Url.Action("TestModelUpdate","TestController")',
async:true,
type:"POST",
contentType: 'application/json',
dataType:"json",
data: JSON.stringify(javaModel)
});
}
</script>
//This is your controller action on the server, and it will autobind your values
//to the newTestModel on post.
[HttpPost]
public ActionResult TestModelUpdate(TestModel newTestModel)
{
TestModel.UpdateTestModel(newTestModel);
return //do some return action;
}
I think you need to explicitly pass the data attribute. One way to do this is to use the
data = $('#your-form-id').serialize();
This post may be helpful.
Post with jquery and ajax
Have a look at the doc here..
Ajax serialize
you can create a variable and send to ajax.
var m = { "Value": #Model.Value }
$.ajax({
url: '<%=Url.Action("ModelPage")%>',
type: "POST",
data: m,
success: function(result) {
$("div#updatePane").html(result);
},
complete: function() {
$('form').onsubmit({ preventDefault: function() { } });
}
});
All of model's field must bo ceated in m.
In ajax call mention-
data:MakeModel(),
use the below function to bind data to model
function MakeModel() {
var MyModel = {};
MyModel.value = $('#input element id').val() or your value;
return JSON.stringify(MyModel);
}
Attach [HttpPost] attribute to your controller action
on POST this data will get available