Pass Object Parameter from javascript\ajax to function in Controller - asp.net-mvc

I have a table that i want to be able to update the status of each line that checkbox is on
(see attached screenshot)
The checkbox propery in the Model is Not Mapped to the database ([NotMapped])
Html:
<div class="row">
<div class="col-12 text-right">
<button class="btn btn-primary" onclick="ApproveStatus()">Approve Checked Lines</button>
</div>
</div>
javaScript:
#section Scripts{
<script type="text/javascript">
function ApproveStatus() {
var pdata = new FormData();
swal({
title: "Are you sure?",
text: "Once Updated, you will not be able to Undo this",
icon: "warning",
buttons: true,
dangerMode: true,
})
.then((willDelete) => {
if (willDelete) {
$.ajax({
url: "PaymentHistory/ApproveStatus",
type: "POST",
data: pdata,
processData: false,
contentType: false,
success: function (data) {
swal("Success!", {
icon: "success",
});
}
});
setTimeout(function () {
location.reload()
}, 100);
} else {
swal("Nothing Changed!");
}
});
}
</script>
}
And in the Controller i have the function (haven't written the logic yet)
[HttpPost]
public IActionResult ApproveStatus()
{
}
table in html:
<table id="tblData" class="table table-striped table-bordered" style="width:100%">
<thead class="thead-dark">
<tr class="table-info">
<th>Address</th>
<th>Payment Type</th>
<th>Amount</th>
<th>Payment Date</th>
<th>Status</th>
<th></th>
</thead>
#foreach (PaymentHistory paymentHistory in Model)
{
<tr>
<td>#ViewBag.getPaymentAddress(paymentHistory.SentFromAddressId).ToString()</td> <td>#ViewBag.getPaymentType(paymentHistory.SentFromAddressId).ToString()</td>
<td>#paymentHistory.Amount$</td>
<td>#paymentHistory.PayDate</td>
<td>#paymentHistory.Status</td>
#if (paymentHistory.Status != "Approved")
{
<td>
<div class="text-center">
<input type="checkbox" asp-for="#paymentHistory.isChecked"/>
</div>
</td>
}
else
{
<td></td>
}
</tr>
}
</table>
My only issue is that i want to pass the Object from the View (that contains the lines and status of the checkbox) to the function in the controller as a parameter,
Any ideas how can i do this?
Thank you

i want to pass the Object from the View (that contains the lines and status of the checkbox) to the function in the controller as a parameter, Any ideas how can i do this?
To achieve your requirement, you can try to add a hidden field for SentFromAddressId field, like below.
<td>
<div class="text-center">
<input type="hidden" asp-for="#paymentHistory.SentFromAddressId" />
<input type="checkbox" asp-for="#paymentHistory.isChecked" />
</div>
</td>
then you can get the sentFromAddressId of each checked row and populate it in form data object.
var pdata = new FormData();
$("input[name='paymentHistory.isChecked']:checked").each(function (index, el) {
var sentFromAddressId = $(this).siblings("input[type='hidden']").val();
pdata.append("Ids", sentFromAddressId);
})
and post the data to action method with following code snippet.
$.ajax({
type: 'POST',
url: '/PaymentHistory/ApproveStatus',
data: pdata,
processData: false,
contentType: false,
datatype: 'json',
success: function (res) {
//...
}
});
ApproveStatus action method
public IActionResult ApproveStatus(int[] Ids)
{
//code logic here
//update corresponding record based on id within Ids

Get all checked checkboxes id in an array, use that array to update table

Related

checkbox value always showing null value in mvc

I am always getting null value through checkbox in mvc. If the checkbox is checked or uncheck it contain null value only.
Here is my code,
View Page
#model IEnumerable<SchoolWebApplication.Models.EventMaster>
<table id="tblEvent" class="table" cellpadding="0" cellspacing="0">
<tr>
<th style="width:100px; display:none">Event Id</th>
<th style="width:150px">Event</th>
<th style="width:150px">Active</th>
</tr>
#if(Model != null)
{
foreach (SchoolWebApplication.Models.EventMaster eventMaster in Model)
{
<tr>
<td class="EventID" style="display:none">
<span>#eventMaster.EventID</span>
</td>
<td class="Event">
<span style="color:darkgreen">#eventMaster.Event</span>
<input type="text" value="#eventMaster.Event" style="display:none; color:darkgreen" />
</td>
<td class="IsActive">
<span style="color:darkgreen">#eventMaster.IsActive</span>
#if (#eventMaster.IsActive == true)
{
<input type="checkbox" value="#eventMaster.IsActive" style="display:none; color:darkgreen" checked="checked" name="abc"/>
}
else
{
<input type="checkbox" value="#eventMaster.IsActive" style="display:none; color:darkgreen" name="abc"/>
}
</td>
<td>
<a class="Edit" href="javascript:;">Edit</a>
<a class="Update" href="javascript:;" style="display:none">Update</a>
<a class="Cancel" href="javascript:;" style="display:none">Cancel</a>
</td>
</tr>
}
}
</table>
<script type="text/javascript">
function AppendRow(row, EventID, Event, IsActive) {
//Bind EventID.
$(".EventID", row).find("span").html(EventID);
//Bind Event.
$(".Event", row).find("span").html(Event);
$(".Event", row).find("input").val(Event);
//Bind IsActive.
$(".IsActive", row).find("span").html(IsActive);
$(".IsActive", row).find("input").val(IsActive);
$("#tblEvent").append(row);
};
//Edit event handler.
$("body").on("click", "#tblEvent .Edit", function () {
var row = $(this).closest("tr");
$("td", row).each(function () {
if ($(this).find("input").length >= 0) {
$(this).find("input").show();
$(this).find("span").hide();
}
});
row.find(".Update").show();
row.find(".Cancel").show();
$(this).hide();
});
//Update event handler.
$("body").on("click", "#tblEvent .Update", function () {
var row = $(this).closest("tr");
$("td", row).each(function () {
if ($(this).find("input").length >= 0) {
var span = $(this).find("span");
var input = $(this).find("input");
span.html(input.val());
span.show();
input.hide();
}
});
row.find(".Edit").show();
row.find(".Cancel").hide();
$(this).hide();
var event = {};
event.EventID = row.find(".EventID").find("span").html();
event.Event = row.find(".Event").find("span").html();
event.IsActive = row.find(".IsActive").find("span").html();
$.ajax({
type: "POST",
url: "/Event/Update",
data: JSON.stringify({ eventMaster: event }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
alert(response.IsActive);
}
});
});
</script>
Controller
try
{
EventMaster updatedEvent = (from c in entities.eventMaster
where c.EventID == eventMaster.EventID
select c).FirstOrDefault();
updatedEvent.Event = eventMaster.Event;
updatedEvent.IsActive = eventMaster.IsActive;
entities.SaveChanges();
return new EmptyResult();
}
catch (Exception ex)
{
return View();
}
Now, in table there is a three field EventID, Event and Active. In active there is a checkbox containing at update time.
Now, the issue is coming that if the checkbox is check or not check it is containing null value only.
So thats why at the fetch time it showing uncheck only.
Thank You.
Asking for the .val of a checkbox will get you the contents (if any) of the value attribute on the input element - this will not change when the user checks the box.
To check if a checkbox is checked in jQuery you should use something like:
if (input.is(":checked")){}
At the moment, you're storing the current value of .IsActive in the span and the value of the checkbox, and then when the update method runs, just grabbing that same value and putting it into the span - resulting in not updating anything.
Looking further at your code though - you should confirm what your method is actually posting back to the server - looking at it you are passing raw HTML into some parameters on the object:
event.IsActive = row.find(".IsActive").find("span").html();
At best, event.IsActive will be the string "True" (or False), rather than an actual boolean that your model is expecting. You would be better off changing that line to something like:
event.IsActive = row.find(".IsActive").find("input").is(":checked");
And then confirm what is being sent to the server in the network tab of your browser.

Partial View Not Rendering inside div

So I was trying to follow this guide and the followup article.
But Before I started with the searching, sorting and filtering, I wanted to see if even the pages were working as intended.
Unfortunately they are not and I cant for the life of me figure it out why, I even went so far as to download his working example just to see if it was something with my browser. (To download his working example its at the top of the second article, I cant post more then 2 links)
Since his worked I compared his views, controllers and scripts side by side to mine and from what I can tell they mirror each other.
So I ended up copying my code somewhere else and pasted his into my project, changed the ActionLinks to reflect the naming conventions I used and left out the stuff I havent implemented yet (noted above). And it still do sent work.
When I run them side by side I get no errors in the console, they are loading the same scripts with the exception that I added jquery.unobstrusive-ajax.js as an attempt to correct it from searching for solutions, but it didnt help.
I have no idea what I'm doing wrong here :/
My Manage View - Correlates to his Home Index View
The only thing I really changed here is the action link
#{
ViewBag.Title = "Home Page";
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/bootstrap")
<script src="~/Scripts/ModalDialog.js"></script>
<style>
.testClass {
font-size: xx-large;
text-transform: capitalize;
}
</style>
<title>
Complete example of MVC pagination, filtering and sortig inside patial view with edit in modal dialog
</title>
</head>
<body style="padding-top:0">
<table style="width:100%;" border="1" cellspacing="0" cellpadding="0">
<tr>
<td style="" colspan="2">
<div id="logo" style="height:70px; background-color:rgba(86, 111, 111, 1);font: 1.5em Georgia, Times New Roman, Times, serif;">
Complete example of MVC pagination, filtering and sortig inside patial view with edit in modal dialog
</div>
<div id="navigation" style="background-color:#a4c2c2">
HOME
</div>
</td>
</tr>
<tr style="height:600px">
<td style="width:200px;background-color: #a4c2c2; vertical-align:top; padding-top:10px; padding-left:10px">
<div>
<ul>
<li>
#Html.ActionLink("Manage Assets", "MasterDetail", "Assets", new { }, new { id = "btnCustomers", #class = "btn btn-default btn-xs" })
</li>
</ul>
</div>
</td>
<td>
<div id="contentFrame" style="width:100%; height:600px; padding-top:10px; padding-left:10px" />
</td>
</tr>
</table>
</body>
</html>
<script type="text/javascript">
$(function () {
$.ajaxSetup({cache : false})
$('#btnCustomers').click(function () {
$('#contentFrame').mask("waiting ...");
$('#contentFrame').load(this.href, function (response, status, xhr) {
$('#contentFrame').unmask("waiting ...");
});
return false;
});
});
</script>
My MasterDetail View - Correlates to his Customers Index view
My table is setup different because i havent done everything he has yet
#using PagedList.Mvc
#model PagedList.IPagedList<Furst_Alpha_2._0.Models.Quantities>
#{
Layout = null;
}
#Styles.Render("~/Content/css")
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/bootstrap")
<script src="~/Scripts/ModalDialog.js"></script>
<h2>Inventory Management</h2>
<p>
#Html.ActionLink("Create New", "_Create", new { id = -1 }, new { btnName = "btnCreate", #class = "btn btn-default btn-xs" })
</p>
<table class="table">
<tr>
<th>
Category
</th>
<th>
Make
</th>
<th>
Model
</th>
<th>
Type
</th>
<th>
Length
</th>
<th>
Width
</th>
<th>
Height
</th>
<th>
Weight
</th>
<th>
Description
</th>
<th>
Rental Price
</th>
<th>
Number Of Techs
</th>
<th>
Total
</th>
<th>
In User
</th>
<th>
Availability
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Assets.Category.CategoryName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Make.MakeName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Model.ModelName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Type.TypeName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Length)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Width)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Height)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Weight)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.Description)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.RentalPrice)
</td>
<td>
#Html.DisplayFor(modelItem => item.Assets.NumTechsReq)
</td>
<td>
#Html.DisplayFor(modelItem => item.total)
</td>
<td>
#Html.DisplayFor(modelItem => item.InUse)
</td>
<td>
#Html.DisplayFor(modelItem => item.Availability)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.QuantityId }, new { btnName = "btnEdit", #class = "btn btn-default btn-xs" })
#Html.ActionLink("Delete", "Delete", new { id = item.QuantityId }, new { btnName = "btnDelete", #class = "btn btn-default btn-xs" })
</td>
</tr>
}
</table>
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
<div id="myPager">
#Html.PagedListPager(Model, page => Url.Action("MasterDetail", new { page, OrderID = ViewBag.OrderID }))
</div>
<script type="text/javascript">
$(function () {
$.ajaxSetup({ cache: false });
setDialogLink($('a[btnName=btnCreate]'), 'Add New Asset', 500, 600, "contentFrame", "/Assets/MasterDetail");
setDialogLink($('a[btnName=btnEdit]'), 'Edit Customer', 500, 600, "contentFrame", "/Customers/Index");
setDialogLink($('a[btnName=btnDetails]'), 'Customer Details', 500, 600, "contentFrame", "/Customers/Index");
$('a[btnName=btnDelete]').click(function (e) {
e.preventDefault();
var confirmResult = confirm("Are you sure?");
if (confirmResult)
{
$('#contentFrame').mask("waiting ...");
$.ajax(
{
url: this.href,
type: 'POST',
data: JSON.stringify({}),
dataType: 'json',
traditional: true,
contentType: "application/json; charset=utf-8",
success:function(data)
{
if (data.success) {
$('#contentFrame').load("/Customers/Index");
}
else {
alert(data.errormessage);
}
$('#contentFrame').unmask("waiting ...");
},
error: function (data) {
alert("An error has occured!!!");
$('#contentFrame').unmask("waiting ...");
}
});
}
})
$("a[btnName=FilterCustomer]").click(function (e) {
e.preventDefault();
var search = $('input[name=search]').val();
this.href = this.href.replace('xyz', search);
$('#contentFrame').mask("waiting ...");
$.ajax({
url: this.href,
type: 'POST',
cache: false,
success: function (result) {
$('#contentFrame').unmask("waiting ...");
$('#contentFrame').html(result);
}
});
});
$(".SortButton").click(function (e) {
e.preventDefault();
$('#contentFrame').mask("waiting ...");
$.ajax({
url: this.href,
type: 'POST',
cache: false,
success: function (result) {
$('#contentFrame').unmask("waiting ...");
$('#contentFrame').html(result);
}
})
});
$('#myPager').on('click', 'a', function (e) {
e.preventDefault();
$('#contentFrame').mask("waiting ...");
$.ajax({
url: this.href,
type: 'GET',
cache: false,
success: function (result) {
$('#contentFrame').unmask("waiting ...");
$('#contentFrame').html(result);
}
});
});
});
</script>
My AssetsController Manage and MasterDetail methods which correlate to his HomeController Index and CustomerController Index methods respectively.
// GET: Assets
public ActionResult Manage()
{
return View();
}
// GET: MasterDetail
public ActionResult MasterDetail(int? page)
{
ApplicationUser user = System.Web.HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(User.Identity.GetUserId());
//ApplicationUser user = db.Users.First(u => u.Id == userr.Id);
var assets = db.Quantities.Where(a => a.VendorId == user.VendorId).OrderByDescending(a => a.AssetId);
int pageNumber = page ?? 1;
int pageSize = 3;
return PartialView(assets.ToPagedList(pageNumber, pageSize));
}
I am not too sure about what your problem is, but I THINK there I saw a problem in your code.
in MasterDetail.cshtml try replacing
#Html.PagedListPager(Model, page => Url.Action("_MasterDetail", new { page, OrderID = ViewBag.OrderID }))
with
#Html.PagedListPager(Model, page => Url.Action("MasterDetail", new { page, OrderID = ViewBag.OrderID }))
Url.Action expects an Action name, not a razor view name.
So last night while laying in bed stumped as to whats causing the problem I thought well maybe I should just look up alternatives. I saw some Ajax variations (that youll see commented out) and I ended up on this SO thread which ultimately lead me to a solution.
Below is the end result of my tinkering, I left commented code in from my attempts so you'll see other thigns I've tried. Other than this all I changed in the view was add a reference for a modal wait screen and then changed Html.ActionLink to a button. <input id="btnCustomers" type="button" value="Manage Assets" />
<script type="text/javascript">
$(function () {
$.ajaxSetup({cache : false})
$('#btnCustomers').click(function () {
//$('#contentFrame').mask("waiting ...");
waitingDialog.show("Please wait while we prepare your inventory ...");
$('#contentFrame').load('#Url.Action("MasterDetail","Assets")', function () {
setTimeout(function () {
waitingDialog.hide();
}, 1000);
});
//$.ajax({
// type: 'GET',
// url: '#Url.Content("~/Assets/MasterDetail")',
// data: -1,
// success: function (data) {
// $('#contentFrame').innerHtml = waitingDialog.hide();
//$('#contentFrame').load('#Url.Action("MasterDetail","Assets")');
// }
//})
//$('#contentFrame').load(this.href, function (response, status, xhr) {
// $('#contentFrame').unmask("waiting ...");
//});
return false;
});
});
</script>

Connecting MVC Model View with associated Knockout.js ViewModel

Background: I'm pretty new to MVC & Knockout.js but I am trying to get up to speed on these technologies. I am using MVC 5 with EF6 and Knockout.JS 3.2.
I have a Detail view that pulls a "VoteAnswer" object using MVC based on the ID passed in the URL:
For example I can go to the url MyDomain/VoteAnswers/Details/1 and it will pull the information from my database correctly (It pulls a VoteAnswer with the ID of 1) and display in my Details view. However I am trying to hook-up my Knockout.js "VoteAnswer" ViewModel to function the same way and am having trouble.
Here is my Details View: (Note the #Html.DisplayFor(model => model.VoteAnswerId) etc works and displays the data from my Database.
#model AM_SPA_TestSite.Models.VoteAnswer
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Details</title>
<script src="~/KnockoutViewModels/VoteAnswers.js"></script>
</head>
<body>
<div>
<h4>VoteAnswer</h4>
<hr />
<table>
<tr>
<td>Id</td>
<td data-bind="text: id"></td>
</tr>
<tr>
<td>Display Text</td>
<td data-bind="text: isActive"></td>
</tr>
<tr>
<td>IsActive</td>
<td data-bind="text: displayText"></td>
</tr>
</table>
<table>
<tr>
<td>Id</td>
<td><input type="text" data-bind="value: id" /></td>
</tr>
<tr>
<td>Display Text</td>
<td><input type="text" data-bind="value: displayText" /></td>
</tr>
<tr>
<td>IsActive</td>
<td><input type="text" data-bind="value: isActive" /></td>
</tr>
</table>
<table>
<tr>
<td>Id</td>
<td>#Html.DisplayFor(model => model.VoteAnswerId)</td>
</tr>
<tr>
<td>Display Text</td>
<td>#Html.DisplayFor(model => model.DisplayText)</td>
</tr>
<tr>
<td>IsActive</td>
<td>#Html.DisplayFor(model => model.IsActive)</td>
</tr>
</table>
</div>
Here is my Knockout.Js ViewModel
// VoteAnswer ViewModel
var VoteAnswerVM = {
id: ko.observable(),
displayText: ko.observable(),
isActive: ko.observable(),
SaveVoteAnswer: function () {
$.ajax({
url: '/VoteAnswers/Create',
type: 'post',
dataType: 'json',
data: ko.toJSON(this),
contentType: 'application/json',
success: function (result) {
},
error: function (err) {
if (err.responseText == "Creation Failed")
{ window.location.href = '/VoteAnswers/Index/'; }
else {
alert("Status:" + err.responseText);
window.location.href = '/VoteAnswers/Index/';;
}
},
complete: function () {
window.location.href = '/VoteAnswers/Index/';
}
});
}
};
//Go
$(document).ready(function () {
//initialize and create new VoteAnswerVM by URL value here?
ko.applyBindings(VoteAnswerVM);
});
I know what I am missing is initializing the ViewModel with the ID of 1, but I was thinking the MVC model already has the data and the knockout.js SHOULD map to that data without manually initializing by sending a request to the database again. What am I missing? thanks.
EDIT: Added solution below. I'm not sure I am settled on this approach but here it is. Updated the controller to ONLY return a view and not query the DB. (otherwise I would have two database calls for the same data.
// GET: VoteAnswers/Details/5
public ViewResult Details(int? id)
{
return View();
}
Added an API Controller that does query the DB.
// GET: api/VoteAnswers/5
[ResponseType(typeof(VoteAnswer))]
public async Task<IHttpActionResult> GetVoteAnswer(int id)
{
VoteAnswer voteAnswer = await db.VoteAnswers.FindAsync(id);
if (voteAnswer == null)
{
return NotFound();
}
return Ok(voteAnswer);
}
In my View (.cshtml file) I reference my knockout.js ModelView, View is Below:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Details</title>
<script src="~/KnockoutViewModels/VoteAnswers.js"></script>
</head>
<body>
<div>
<h4>VoteAnswer</h4>
<hr />
<table>
<tr>
<td>Id</td>
<td data-bind="text: VoteAnswerId"></td>
</tr>
<tr>
<td>Display Text</td>
<td data-bind="text: IsActive"></td>
</tr>
<tr>
<td>IsActive</td>
<td data-bind="text: DisplayText"></td>
</tr>
</table>
<table>
<tr>
<td>Id</td>
<td><input type="text" data-bind="value: VoteAnswerId" /></td>
</tr>
<tr>
<td>Display Text</td>
<td><input type="text" data-bind="value: DisplayText" /></td>
</tr>
<tr>
<td>IsActive</td>
<td><input type="text" data-bind="value: IsActive" /></td>
</tr>
</table>
</div>
<div id="error"></div>
</body>
</html>
Updated My ViewModel script to access the Database based on the URL ID.
// VoteAnswer ViewModel
var VoteAnswer = function () {
var self = this;
self.VoteAnswerId = ko.observable();
self.DisplayText = ko.observable();
self.IsActive = ko.observable();
self.SaveVoteAnswer = function () {
$.ajax({
url: '/VoteAnswers/Create',
type: 'post',
dataType: 'json',
data: ko.toJSON(this),
contentType: 'application/json',
success: function (result) {
},
error: function (err) {
if (err.responseText == "Creation Failed")
{ window.location.href = '/VoteAnswers/Index/'; }
else {
alert("Status:" + err.responseText);
window.location.href = '/VoteAnswers/Index/';;
}
},
complete: function () {
window.location.href = '/VoteAnswers/Index/';
}
});
}
self.load = function (id) {
if (id != 0) {
$.ajax({
url: '/api/VoteAnswers/' + id,
type: 'get',
data: ko.toJSON(this),
contentType: 'application/json',
success: function(data) {
self.VoteAnswerId = ko.observable(data.voteAnswerId);
self.DisplayText = ko.observable(data.displayText);
self.IsActive = ko.observable(data.isActive);
ko.applyBindings(self);
},
error: function(err) {
if (err.responseText == "Creation Failed") {
window.location.href = '/VoteAnswers/Index/';
} else {
$("#error").text("Status:" + err.responseText);
//window.location.href = '/VoteAnswers/Index/';;
}
},
complete: function() {
//window.location.href = '/VoteAnswers/Index/';
}
});
} else {
window.location.href = '/VoteAnswers/Index/';
}
}
};
function GetURLParameter() {
var sPageUrl = window.location.href;
var indexOfLastSlash = sPageUrl.lastIndexOf("/");
if (indexOfLastSlash > 0 && sPageUrl.length - 1 != indexOfLastSlash)
return sPageUrl.substring(indexOfLastSlash + 1);
else
return 0;
}
//Go
$(document).ready(function () {
//initialize and create new VoteAnswerVM by URL value here?
var viewModel = new VoteAnswer();
viewModel.load(GetURLParameter());
});
I hope I understood you correctly, if my answer is all wrong for your question let me know where I went wrong.
First thing to realize is, if you bind a KO observable to an input field, knockout will not look at the initial value of that input field and store it in the observable. It will do the opposite: it will look at the current value in the observable and store it in the input field's value. In your case, the observable are initialized without a value, which in JavaScript means the value undefined. So if you bind your observables to the fields you've filled with Razor/MVC viewmodel, you'll immediatly overwrite those values with the empty values stored in your observables.
There IS a way to fill your Knockout model with your data through Razor, but it involves inline JavaScript and is a bad practise for a number of reasons (I will elaborate on this on request).
The best way to do this is to separate your views from your data: Don't inject the MVC viewmodel into the view, but make a separate endpoint that returns JSON and return the data there (this endpoint will receive the ID parameter instead of the view). The JSON endpoint is called from JavaScript and can be used to fill your model with the correct values.
Upsides: separation of concerns, possibility to enable view caching for a more responsive frontend, no need to use razor syntax, or even worse, combine it with inline JS. All your binding of data to the UI will happen through Knockout. I learned this myself because we also started out using razor, but on the long run this solution wasn't feasible for a big project. We never regretted the switch to always getting the data from separate JSON endpoints.
If you are unsure on how to do this I can write some pseudocode to illustrate the idea.
These may be the possible solutions
1.) data_bind is wrongly used
<td><input type="text" data-bind="value: isActive" /></td> // which is wrong
<td><input type="text" data_bind="value: isActive" /></td> //data_bind is wrongly used
2.)
If still problem exists you may try this syntax
#Html.DisplayFor(model => model.IsActive, new { data_bind = "value:IsActive" });
If you find still something missing please provide some detail info .

Update main viewmodel when partial view updated via ajax post

I am trying to get the viewmodel on the page to update when a partial view is updated via an ajax post. The partial view updates correctly but on the next update call the model seesm to have reverted back to the orginal state.
The partial view is a table and I am either adding or deleting a row. The codde is included below any ideas as to how this can be done.
page code is
<div class="filters">
<fieldset class="source">
<legend>Search Attributes</legend>
<div id="attributes-filter">
#Html.Partial("_EditSearchQuery")
</div>
</fieldset>
</div>
<div>
<a id="addRowLink" class="add-row-link" href="#">Add new clause</a>
</div>
</div>
</div>
-- partial view is
<table id="searchClauses" class="clauses">
<tbody>
<tr class="header">
<td class="add-remove"></td>
<td class="logical">And/Or</td>
<td class="field">Field</td>
<td class="operator">Operator</td>
<td class="value">Value</td>
</tr>
#foreach (SearchClause item in Model.searchClauses)
{
<tr class="clause clause-row" id=#item.RowID>
<td class="add-remove">
<a href="#" title="Remove this filter line" id=#item.ID >Delete</a>
</td>
<td>
#Html.DropDownListFor(modelitem => item.logicalTypeValue, new SelectList(item.logicalTypeList, "Value", "Text", "Selected"), new { style = "width: 60px" })
</td>
<td>
#Html.DropDownListFor(modelitem => item.fieldListValue, new SelectList(item.fieldList, "Value", "Text", "Selected"))
</td>
<td>
#Html.DropDownListFor(modelitem => item.operatorListValue, new SelectList(item.operatorList, "Value", "Text", "Selected"), new { style = "width: 60px" })
</td>
<td>
#Html.TextBoxFor(modelitem => item.valuesList[0], new { style = "width: 130px" })
</td>
</tr>
}
</tbody>
-- script
<script type="text/javascript">
$(function () {
// Save quiz view - new or existing.
$("#attributes-filter").on("click", "a", function () { // A jQuery delegated event - #EditQuiz is always present, a.SaveQuiz only exists when the _ElearningQuiz partial view is loaded.
deleteRow($(this).attr("id"));
});
function deleteRow (id) {
var rowData = {
'id': id,
'model' : #Html.Raw(Json.Encode(Model))
};
$.ajax({
url: "/Participant/DeleteClause",
type: "POST",
data: JSON.stringify(rowData),
contentType: "application/json; charset=utf-8",
success: function (result) {
$("#attributes-filter").html(result);
},
error: function (jqXHR, textStatus, errorThrown) {
alert("Status: " + textStatus + " Error: " + errorThrown);
}
});
};
$("#addRowLink").click(function () {
var model = #Html.Raw(Json.Encode(Model))
$.ajax({
url: "/Participant/AddClause",
type: "POST",
data: JSON.stringify(model),
contentType: "application/json; charset=utf-8",
success: function (result) {
$("#attributes-filter").html(result);
},
error: function (jqXHR, textStatus, errorThrown) {
alert("Status: " + textStatus + " Error: " + errorThrown);
}
});
});
});
</script>
-- controllers
[HttpPost]
public ActionResult AddClause(DynamicSearchModel model)
{
int campaignId = SessionManager.CampaignId;
int clientId = SessionManager.ClientId;
var newClause = _participantServiceClient.NewSearchClause(campaignId, clientId, 2);
newClause.ID = model.searchClauses.Count + 1;
model.searchClauses.Add(newClause);
return PartialView("_EditSearchQuery", model);
}
[HttpPost]
public ActionResult DeleteClause(string id, DynamicSearchModel model)
{
int _id = int.Parse(id);
model.searchClauses.RemoveAt(_id - 1);
return PartialView("_EditSearchQuery", model);
}

Jquery form post Issues

I am using asp.net MVC and I am having an issue posting a form using jquery.
It is not posting to the url I am telling it to.
If I use firebug, it shows the post happening but it is posting to the index of the controller everytime. I cannot figure out why. I have verified the url of the action I am trying to post but I can't figure out why it is always posting to the index of the controller....Note: the view in which the form is found IS the index view. so Basically it is posting to it's own action rather than the one in the url i am telling it to. Any help would be great. thanks!
here is my form
<form action='' id="descriptionForm">
<%=Html.Hidden("claimNumber", ViewData["claimNumber"])%>
<%=Html.Hidden("partNumber", ViewData["partNumber"])%>
<%=Html.Hidden("qty", ViewData["qty"])%>
<table>
<tr>
<td style="text-align: right">
Category:
</td>
<td>
<%=Html.DropDownList("problemCategory", (IEnumerable<SelectListItem>)ViewData["problemSelect"], "-Select-")%>
</td>
</tr>
<tr>
<td style="text-align: right">
Details:
</td>
<td>
<select id="problemDetails">
</select>
</td>
</tr>
<tr>
<td style="text-align: right">
Dealer Notes:
</td>
<td>
<%=Html.TextArea("dealerNotes", "", 3, 40, null)%>
</td>
</tr>
</table>
<div style="position: absolute; bottom: 8px; right: 8px">
<input type="button" id="itemDetailsCancel" value="Cancel" />
<input type="submit" id="itemDetailsSubmit" value="Save" />
</div>
</form>
<a href='<%=ResolveUrl("~/Warranty/WarrantyClaims/CompleteAddLineItemToClaim/") %>'
id="CompleteLineItemUrl"></a>
Here is my Javascript
$("#descriptionForm").submit(function () {
var completeurl = $("#CompleteLineItemUrl").attr('href');
var data = $(this).serialize();
$.post({
type:'POST',
url: completeurl,
data: data,
success: function (result) {
alert("done");
}
});
return false
});
and just for good measure here is the controller action I am trying to post to(though it doesn't do much yet)
[HttpPost]
public ActionResult CompleteAddLineItemToClaim(string claimNumber, string partNumber, string qty, string problemCategory, string problemDetails, string dealerNotes)
{
var result = new { result = "done" };
return Json(result, JsonRequestBehavior.AllowGet);
}
Update:
updated javascript
$(function(){
$('#descriptionForm').submit(function () {
var completeurl = $('#CompleteLineItemUrl').attr('href');
var data = $(this).serialize();
$.ajax({
type: 'POST',
url: completeurl,
data: data,
success: function (result) {
alert('done');
}
});
return false;
});
});
Is the form itself loaded by an ajax call?
If so you need to use the live() function of jquery.
Make sure you have wrapped your javascript in a document.ready before subscribing for any events. Also you have a missing ; when returning false at the end of your method.
But your real problem is that you want to use $.ajax instead of $.post. So what actually happens is that you are getting a javascript error because of wrongly using the $.post function and the .submit handler never has time to return false and cancel the default submission of the form and the browser happily proceeds into POSTing to the action of the form (which is empty and default to the action that rendered this form).
So to sum up:
$(function() {
$('#descriptionForm').submit(function () {
var completeurl = $('#CompleteLineItemUrl').attr('href');
var data = $(this).serialize();
$.ajax({
type: 'POST',
url: completeurl,
data: data,
success: function (result) {
alert('done');
}
});
return false;
});
});
Or if you wanted to use $.post:
$(function() {
$('#descriptionForm').submit(function () {
var completeurl = $('#CompleteLineItemUrl').attr('href');
var data = $(this).serialize();
$.post(completeurl, data, function (result) {
alert('done');
});
return false;
});
});
Also instead of generating links à la classic WebForms way:
In ASP.NET MVC you use HTML helpers in order to ensure that link urls are conform to your routes:
<%= Html.ActionLink(
"Link text",
"CompleteAddLineItemToClaim",
"WarrantyClaims",
new { area = "Warranty" },
new { id = "CompleteLineItemUrl" }
) %>

Resources