Jquery sortable index change to ASP.NET MVC controller - asp.net-mvc

I am trying to get the model binder to recognize the change. I am not sure what I am missing here. Basically the initial page population pulls the page number from the database. I then have the sortable working, the raw HTML in Firebug shows the change in order. But when I post back to the model first off it is not figuring out to go the post method and the other issue is Survey. Pages does not seem to have the change in order.
View
#for (var i = 0; i < Model.Pages.Count; i++)
{
var page = Model.Pages.ElementAt(i);
#Html.Hidden("Pages[" + i + "].PageId", page.PageId, new { #class = "page_index" })
#Html.Hidden("Pages[" + i + "].PageNumber", page.PageNumber)
<li id="#page.PageId" class="sortable-item text-center ui-state-default"><span class="ui-icon ui-icon-arrowthick-2-n-s">
</span>#page.PageNumber</li>
}
</ul>
JavaScript
<script type="text/javascript">
$(document).ready(function () {
$('.sortable').sortable({
stop: function (event, ui) {
var formData = $('#editSurveryForm').serialize();
$.ajax({
url: "#Url.Action("Edit")",
data: formData,
type: 'POST',
traditional: true,
success: function () {
alert("success");
},
error: function () {
alert("fail");
}
}
);
}
});
});
</script>
Controller
[HttpPost]
public ActionResult Edit(Survey survey)
{
if (!ModelState.IsValid)
{
return View("EditSurvey", survey);
}
surveyRepository.UpdateSurvey(survey);
return RedirectToAction("Index", "Administration");
}

Ok, I figure this one out. I had the hidden fields outside of the <li></li> tag. Once I moved them inside I did all my logic as I would have.
<div class="span9">
<div class="span4">
<ul class="sortable_page_list">
#for (var i = 0; i < Model.Pages.Count; i++)
{
<li class="sortable-item text-center ui-state-default">
#Html.HiddenFor(model => model.Pages[i].PageId)
#Html.HiddenFor(model => model.Pages[i].PageNumber)
<span class="ui-icon ui-icon-arrowthick-2-n-s"></span>#Model.Pages[i].PageNumber
</li>
}
</ul>
<div class="span1 pull-right internal-wrapper">
#Html.ActionLink("Add", "AddPage", new { id = Model.SurveyId }, new { #class = "add_survey_icon common_icon_settings" })
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$('.sortable_page_list').sortable({
update: function (event, ui) {
var counter = 1;
$("[id*='PageNumber']").each(function() {
$(this).attr("value", counter);
counter++;
});
//var surveyToUpdate = $('#editSurveyForm');
$.ajax({
url: '#Url.Action("Edit","Administration")',
contentType: "application/json; charset=utf-8",
data: $('#editSurveyForm').serialize(),
type: 'POST'
});
}
});
});
Last thing to figure out is why the ajax post is not posting to the Post method with the survey form data

Related

Button click data-bind is not working with knockout

I cannot get the following piece of code to fire the button click to call save. I am using ASP.Net MVC with Knockoutjs. I am new to knockout and mvc. What am I missing here? Thanks in advance.
cshtml
#section scripts
{
<script src="~/Scripts/knockout-3.4.0.js"></script>
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<script src="~/CustomScripts/bookingviewmodel.js"></script>
<script type="text/javascript">
var bookingViewModel = new BookingViewModel(#Html.Raw(data));
ko.applyBindings(bookingViewModel);
</script>
}
<div class="content">
<button class="btn btn-primary pull-right" data-bind="click: save"><i class="fa fa-check"></i> Save Booking</button>
</div>
bookingviewmodel.js
BookingViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
self.save = function () {
$.ajax({
url: "/Booking/Save",
type: "POST",
data: ko.toJSON(self),
contentType: "application/json",
success: function (data) {
if (data.bookingViewModel != null) {
ko.mapping.fromJS(data.bookingViewModel, {}, self);
}
}
});
}
}

MVC partial in modal posting wrong model

My partial view which is loaded into a bootstrap partial on my Index page, should be posting type Announcement but is posting type AnnouncementViewModel of the Index page model to the Create controller.
The #modal-container is specified in my _Layout, which is working as expected.
Unsure about the controllers - they appear correct, the problem is stemming from my ajax post I believe but I don't know what's the issue. I get the error after POST, however the database does update with the model correctly, but afterwards I get the below error.
I have specified $('#create-container')/$('form') as the form in which to serialize and send back to the controller.
Why is it doing this?
Error:
The model item passed into the dictionary is of type 'AnnouncementsViewModel', but this dictionary requires a model item of type 'Announcement'.
Index:
#model AnnouncementsViewModel
<h2>Announcements</h2>
<div>
#Html.ActionLink("Create", "Create", "Announcements", null, new { #class = "modal-link btn btn-sm" })
<div class="announcementTable">
<div id="announcementList">
#{Html.RenderPartial("List", Model.AnnouncementList);}
</div>
</div>
</div>
Partial:
#model Announcement
#section Scripts {
<script type="text/javascript">
$(function () {
$('#btn-create').click(function () {
$.ajax({
url: '#Url.Action("Create","Announcements")',
type: 'POST',
contentType: 'application/json',
data: $('#create-container').serialize(),
success: function (data) {
if (data.success == true) {
$('#modal-container').modal('hide');
location.reload(false)
} else {
$('#modal-container').html(data);
}
}
})
});
$('#btn-close').click(function () {
$('#modal-container').modal('hide');
});
});
</script>
}
<div class="create-container">
#using (Html.BeginForm())
{
<div class="newAnnouncementTableRow1">
<div>#Html.LabelFor(m => m.Title)</div>
<div>#Html.EditorFor(m => m.Title)</div>
<div>#Html.LabelFor(m => m.Details)</div>
<div>#Html.EditorFor(m => m.Details)</div>
</div>
<div class="newAnnouncementTableRow2">
<div>#Html.LabelFor(m => m.StartDT)</div>
<div>#Html.EditorFor(m => m.StartDT)</div>
<div>#Html.LabelFor(m => m.ExpiryDT)</div>
<div>#Html.EditorFor(m => m.ExpiryDT)</div>
<div>#Html.LabelFor(m => m.Enabled)</div>
<div>
#Html.RadioButtonFor(m => m.Enabled, 1)Yes
#Html.RadioButtonFor(m => m.Enabled, 0, new { #checked = "checked" })No
</div>
</div>
<div>
<button type="submit" id="btn-create" class="btn btn-sm">Save</button>
<button type="button" class="btn btn-default modal-close-btn" data-dissmiss="modal">Cancel</button>
</div>
}
</div>
Controller:
[HttpGet]
public ActionResult Index()
{
var avm = new AnnouncementsViewModel
{
AnnouncementList = new List<Announcement>()
};
avm.AnnouncementList = GetAnnouncementList();
return View(avm);
}
[HttpGet]
public ActionResult Create()
{
return PartialView("Create");
}
[HttpPost]
public ActionResult Create(Announcement a)
{
db.DbAnnouncement.Add(a);
db.SaveChanges();
return Index();
}
You set contentType: 'application/json' it your .ajax() call but returning View from Controller. Either change contentType to html or change controller to return JsonResult and return Json("yourData");
I recommend you to change your ajax call:
$.ajax({
/* other data */
dataType : "html",
contentType: "application/json; charset=utf-8",
/* other data */
success: function (data) {
$('#modal-container').modal('hide');
location.reload(false)
},
error: function (jqXHR, textStatus, errorThrown )
{
$('#modal-container').html(data);
}
/* other data */
});
Thing is response from server in your case always success but it returns html rather than json so you just don't have data.success at all.
The other issue as mentioned in the comments was that the controller was redirecting to an action method that it could not.
Changing return Index(); to return RedirectToAction("Index", "Announcements"); solved the error and the redirecting to the Create partial page caused by using return View();.

Quick Search Form Not Submitting MVC

I currently have a partial view that renders at the top of every page on the site. The point of this partial view is to provide a form that lets the user do a quick search. I have set the partial view form up as follows:
#using (Html.BeginForm())
{
<div class="col-md-7" style="text-align: right">
<div class="input-group input-group-sm col-sm-6 pull-right">
#Html.TextBox("caseReference")
<button type="submit">
<i class="fa fa-search"></i>
</button>
</div>
</div>
}
#Html.Partial("_MainNavigation")
</div>
</div>
</nav>
<script type="text/javascript">
$(function () {
$("form").on("submit", function (event) {
event.preventDefault();
var request = { caseReference: $('#caseReference').val() };
submitForm(request, '#Url.Action("CaseSearch", "QuickSearch", new { area = "Search" })');
});
});
</script>
However under the page source the form action renders as a request to the home page with a post action. I have read numerous examples and this task seems very straight forward. Would it be a better idea to use the parameters on the #html.BeginForm() method?
So after spending a few hours researching, I have finally got the quick search functionality to work on the home page of my site. In the razorview I have the following code:
<div class="input-group input-group-sm col-sm-6 pull-right">
#Html.Kendo().MaskedTextBox().Name("name").Mask("000000/0000").Deferred()
<button id="search" type="submit">
<i class="fa fa-search"></i>
</button>
<script type="text/javascript">
$(function () {
$("#search").on("click", function (event) {
event.preventDefault();
var value = $('#name').val();
value = value.replace(/[/]/g, "_");
var refVal = value;
var url = '#Url.Action("Action", "Contoller", new { area = "Area" })' + '//' + refVal;
$.ajax({
type: 'GET',
url: url,
cache: false,
dataType: 'json',
contentType: "application/json;",
success: function (result) {
if (result.success) {
window.location.href = result.url;
}
else {
bootbox.alert(result.message);
}
}
});
});
});
However in regards to the following line:
var url = '#Url.Action("Action", "Contoller", new { area = "Area" })' + '//' + refVal;
If I hard code the url and append the search term it works on the Home page because we are at the root directory but from other pages it fails, To get around this I tried to use #Url.Action. However this is producing the following result in the html soure code:
var url = '' + '//' + refVal;
Is there a certain way to use the URL.Action method from withing JS?

How can I refresh my razor view on AJAX post

Helo all,
I am able to post to controller using ajax.post, but on success how can I make my view refresh with new data.
Do I need to usn #Html.BeginForm to do this?
This is my view.
<div>
<p>Order lines allocates to <b>#Model.Name (#Model.Code) </b>
</div>
#if (Model.OrderLineAllocations.Any())
{
#grid.GetHtml(
columns: grid.Columns(
grid.Column(header: "Dispatched", style: "row-selector", format: #<text><input name="chkSelected" class="myCheckbox" onclick="expandableEvent(this)" type="checkbox" value="#item.IdAllocation" /></text>),
grid.Column(header: "Order Ref", format: item => item.OrderLineItem.OrderLine.Order.OrderRef)
),
tableStyle: "expandable-table",
rowStyle: "expandable-master-row",
htmlAttributes: new { id = "gridLineAllocations" })
<br />
<input type="hidden" id="hidUnselectedValues" name="hidUnselectedValues" />
<input type="submit" name="action" value="Dispacth" id="btnDispacth" />
<input type="submit" name="action" value="Revert" id="btnRevert" />
}
else
{
#Html.Raw("No records found....");
}
And this is my ajax post
$(document).ready(function() {
unSelected = [];
$("#btnDispacth").click(dipatchAllocations);
$("#btnRevert").click(revertAllocations);
});
function dipatchAllocations() {
var objInputEmail = $("#hidUnselectedValues");
if (objInputEmail != null) {
var id = objInputEmail.val();
if ((id != null) && (id != "")) {
$.ajax({
type: 'POST',
url: '/Batch/GetData',
data: '{ "allocationId" : "' + id + '","batchId" : "' + #Model.Id + '" }',
contentType: "application/json; charset=utf-8",
//contentType:"application/x-www-form-urlencoded",
traditional: true,
success: subscribed,
error: errorInSubscribing
});
} else {
alert('Please enter a valid email address in order to subscribe.');
}
}
};
This is my controller action
[HttpPost]
public ActionResult GetData(long[] allocationId,long batchId)
{
var model = context.GetData(batchId)
model.Name = "asdaksdjaksdj";
return View("Finalize", model);
}
I am having some idea, I have to do that on success call back. But I am not sure how to bind my updated model to the view at client side.
Thanks
There is no simple "rebind" method inside mvc, it's still html, css and js at the end.
I see 2 options to achieve desired behaviour.
option 1. Override rendered content with the result of POST
In this case your View will look similar to:
<div id="content">
<div>
<p>Order lines allocates to <b>#Model.Name (#Model.Code) </b>
</div>
...
else
{
#Html.Raw("No records found....");
}
</div>
On javascript:
$.ajax({
type: 'POST',
url: '/Batch/GetData',
dataType: "html",
success: function(data, textStatus, jqXHR){
$('#content').html(data);
}
});
option 2. Fill rendered html from javascript on every load
This will require to move Razor logic to javascript.
Your view will look like:
<div>
<p>Order lines allocates to <b id="NameAndCode"></b>
</div>
And javascript will fill the gaps:
$(function(){
var model = {
NameAndCode: "#Model.Name (#Model.Code)"
}
fillView(model);
})
var fillView = function(data){
$('#NameAndCode').html(data.NameAndCode)
}
$.ajax({
type: 'POST',
url: '/Batch/GetData',
dataType: "json",
success: function(data, textStatus, jqXHR){
fillView(data);
}
});
It's just a small piece just to show the idea.
It depends on case which option to choose.

Ajax.BeginForm - Get element which makes request

I have some ajax forms in my page and I need to get the form Id or some element inside the form when the OnSuccess function is called, example:
<li>
#using (Ajax.BeginForm(new AjaxOptions
{
OnSuccess = "form.onSuccess"
}))
{
#Html.TextBoxFor(m => m.TaskId)
<button type="submit">Save</button>
}
</li>
how can I get?
Option 1:
#using (Ajax.BeginForm(new AjaxOptions{OnComplete = "DefaultEditOnComplete(xhr, status, 'Person')"}))
{
//Person data and submit button
}
function DefaultEditOnComplete(xhr, status, entityName) {
//xhr - the ajax response
//status - the response text, ex. "success"
//entityName - your custom argument, in this example 'Person'
alert('DefaultEditOnComplete fired for ' + entityName);
}
Option 2:
$('form').submit(function () {
$(this).addClass('activeForm');
});
#using (Ajax.BeginForm(new AjaxOptions{OnSuccess= "JaxSuccess(xhr, status)"}))
{
....
}
function JaxSuccess(xhr, status) {
var active = $(".activeForm");
//Do some stuff here
.....
//When Done, remove the activeForm class, making everything clean
$(".activeForm").removeClass('activeForm');
}
Option 3:
Abandon Ajax.BeginForm, and substitute for regular form and jquery pairing:
#using (Html.BeginForm("SomethingNice", "Home", FormMethod.Post, new { #id = "CoolForm", #class = "ajaxForm" }))
{
#Html.LabelFor(m => m.Rating)
#Html.TextBoxFor(m => m.Rating)
#Html.LabelFor(m => m.Comment)
#Html.TextBoxFor(m => m.Comment)
<input type="submit" value="Submit"/>
}
<script type="text/javascript">
$(function() {
$(".ajaxForm").submit(function(e) {
e.preventDefault();
var form = $(this);
var jaxUrl = form.attr('action');
var dat = form.serialize();
alert(form.attr('id'));
$.ajax({
url: jaxUrl,
data: dat,
success: function(data) {
form.parent().append(data);
},
error: function(xhr, status) {
}
});
});
});
</script>

Resources