Accessing Post method from View through JavaScript - javascript

I am facing problems accessing the ActionResult [Post] from my View.
View:
#using (Html.BeginForm()){
<form id="edit-order-form" action="#Href("~/Orders/Edit")">///EDIT:
....
<div class="row">
<span class="label"><label for="ShipPostalCode">PostalCode:</label></span>
<input type="text" id="txtShipPostalCode" name="ShipPostalCode" value="#ViewBag.ShipPostalCode" />
</div>
<div class="row">
<span class="label"> </span>
<input type="submit" id="btnSave" name="submit" value="Save" />
</div>
</fieldset>
</form>
<script type="text/javascript">
$("#btnSave").live("click", saveRecord);
function saveRecord() {
$.ajax(
{ type: "Post" ,
url: '#Url.Action("Save", "OrdersList")',
data: {
OrderID: $("#hdnOrderID").val(),
ShipName: $("#txtShipName").val(),
ShipAddress: $("#ShipAddress").val(),
RequiredDate: $("#RequiredDate").val(),
ShipPostalCode: $("#ShipPostalCode").val(),
},
dataType: "html" ,
success: function (data){
alert ('saved');
}
}).....
Controller:
[HttpPost]
//[ValidateAntiForgeryToken]
public ActionResult Save(int orderId = 0, string ShipName = "", string ShipAddress = "", string ShipPostalCode = "", DateTime? RequiredDate = null)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString);
using (SqlCommand cmd = new SqlCommand("GetOrders", conn))
{
conn.Open();
//SqlCommand cmd = new SqlCommand( "GetOrders", "connection string");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#ID", orderId);
cmd.Parameters.AddWithValue("#ShipName", ShipName);
cmd.Parameters.AddWithValue("#ShipAddress", ShipAddress);
SqlParameter paramDate = cmd.Parameters.Add("#RequiredDate",
System.Data.SqlDbType.DateTime);
paramDate.Value = RequiredDate;
//cmd.Parameters.AddWithValue("#RequiredDate", RequiredDate);
cmd.Parameters.AddWithValue("#ShipPostalCode", ShipPostalCode);
//SqlParameter Total = cmd.Parameters.Add("#Total", SqlDbType.Int);
//Total.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
conn.Close();
return View();
}
}
The controller action doesn't get called. Probably the javascript function neither.

First what you need to do is change the 'type' attribute of the 'btnSave' input element to 'button' so it doesn't post the page when clicked. 'Input' elements with the type of 'submit' will actually post the page, which is not what you want when you want to execute javascript when a button is clicked.
Next what you'll need to do is use either IE or Chrome and pull up the Developer tools, 'F12'. In Chrome, click the 'Sources' tab, then open the 'Navigator' by clicking the 'boxed arrow' below the 'Elements' tab. Find the file which holds your javascript and breakpoint the line which has the following syntax, $.ajax(. Then go to your page and click the 'Submit' button. From there, you should see exceptions that are most likely causing your javascript to fail.
Also, you may want to open 'Fiddler' and watch to see if the 'Post' to your RESTful service is kicking off.

Have you tried using document.forms[0].submit(); instead? To see if it's a problem with the posting or your javascript?
Also .live is deprecated, you should be using .on instead.
example code:
$("#btnSave").on("click", saveRecord);
//or $("#btnSave").click( function(){
// document.forms[0].submit();
//});
function saveRecord() {
document.forms[0].submit();
})
And change your Save action result's attributes to [HttpPost] and below that [ActionName("Edit")]

Related

"How to 'Reload the only Partial View' part after submitting the form with HTML Helper in jquery?"

I have a partial view on a View of MVC so after Submit the form that is submitting within jquery that you can see below in the code. I have to refresh the Partial view to show some changes that made in partial view after clicking on save button. What should I do in the section of script on click of save?
#using(Html.BeginForm(FormMethod.Post, new{id="form"}))
{
<div>
#Html.Partial("_VehicleCard", Model)
</div>
<div>
<div id="submitBtn" class="row>
#(Model.VehicleCards.Count>0?"":"hidden")">
<div>
<button type="button" id="btnSubmit">Save</button>
</div>
</div>
</div>
}
#section scripts{
<script>
$('#btnSubmit').click(function (event) {
event.preventDefault();
event.stopImmediatePropagation();
$('#form').submit();
//here i wants to refresh Patrial View.
});
</script>
}
Here is my Controller code:
public PartialViewResult GetVehicleForEndMileage(string date, int? Id)
{
try
{
var model = new VehicleEndMilageVM();
DateTime selectedDate;
DateTime.TryParseExact(date, "dd/MM/yyyy", null,
DateTimeStyles.None, out selectedDate);
model.SelectedDate = selectedDate.ToString("dd/MM/yyyy");
model.LocationId = Id ?? 0;
model.VehicleCards =
vehicleDailyInspectionBLL.GetDailyInspectionDetail(selectedDate, Id).Select(x => new VehicleCard
{
VehicleNumber = x.VehicleNumber,
StartMilage = x.StartMilage,
Driver = x.Driver,
EndMilage = x.EndMilage,
VehicleId = x.VehicleId,
VehicleDailyInspectionId = x.VehicleDailyInspectionId,
IsEndMilageAdded = (x.EndMilage !=null && x.EndMilage > 0) ? true : false
}).ToList();
return PartialView("_VehicleCard", model);
}
catch (Exception ex)
{
throw;
}
}
You can simply do it via an ajax call.
First, you have to set an id for <div> tag
<div id="htmlContainer">
#Html.Partial("_VehicleCard", Model)
</div>
Then
$('#btnSubmit').click(function (event) {
event.preventDefault();
event.stopImmediatePropagation();
$('#form').submit();
$.ajax({
url: 'url',
dataType: 'html',
success: function(data) {
$('#htmlContainer').html(data);
}
});
});
You controller seems to be like this :
public PartialViewResult GetVehicleCard(...)
{
return PartialView("_VehicleCard", your view model);
}
HttpPost methods are for SENDING data to the server. You do not need to send your data to the server, rather, you need to GET data from the server with specified criteria and then display it. With that being send, you do not need your HTML.BeginForm() method. Moreover, you do not need to declare a PartialViewResult return type, an ActionResult will suffice. Additionally, you don't need to return the the name of the partial view and the associated model. Simply give the partial view the model results like so:
return PartialView(model)
Next, create an AJAX link on the page you will be clicking your button on like so:
#Ajax.ActionLink("GetVehicleForEndMileage", "Vehicles", new AjaxOptions()
{
HttpMethod = "GET",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "Results"
})
<div id="Results"></div>
You can wrap this link in a button tag to work with your current set-up.
Now just define your Partial View in a separate .cshtml file.
#model ModelName
<div>
// Model attributes to be displayed here.
</div>
Now, embed that partial view within the view you wish to have the callback displayed.
Having said all of that, your javascript/jQuery can be removed.

Use MVC Session to store Client-side values (e.g. filter text) between visits

In an MVC View, is there an efficient way to store client-side values for use on subsequent page visits?
Typical scenario
An Index page has a table that's getting a bit long so I add a filter (I know paging is another option) and use an input control with some JavaScript to limit the table rows without having to perform another "Get" from the server.
This works fine but, if I navigate off (say) into an edit page then return back to the Index page, the filter is clearly no longer there.
After a bit of searching I never found anything simple so I post my meagre answer below.
The View contains a form at the top of the page into which a user can type filter text (on form "Get", text is set from a session value):-
<form id="frmEdit">
#Html.AntiForgeryToken()
<div class="form-group row">
<div class="col-sm-6">
#Html.ActionLink("Create New", "Create", null, new { #class = "nav-item nav-link" })
</div>
<label for="search" class="col-sm-2 col-form-label text-right">Filter</label>
<div class="col-sm-4">
<input type="text" placeholder="Filter" class="form-control" id="search" value=#Session["SparesSectionFilter"]>
</div>
</div>
</form>
A script section contains the filtering JavaScript but also a postback to the controller
#section Scripts{
<script type="text/javascript">
// on load
PerformFilter();
// hook up events
$(function () {
$("input#search").on("keydown keyup", function () {
PerformFilter();
// post back to session for reuse
$.post('SparesSections/Session_Add', { __RequestVerificationToken: $('[name=__RequestVerificationToken]').val(), itemName: 'SparesSectionFilter', itemValue: $("#search").val() });
});
})
</script>
}
I have a custom base-class for my controller into which I've added the following actions. These are usable from any controller using this class. The Razor view loads the session value but I've included a "Get" in the controller for client-side options.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Session_Add(string itemName, string itemValue)
{
Session.Add(itemName, itemValue);
return Json(new { itemName = itemName, itemValue = itemValue }, JsonRequestBehavior.AllowGet);
}
[HttpGet]
public ActionResult Session_Get(string itemName)
{
return Json(new { itemName = itemName, itemValue = Session[itemName] ?? string.Empty }, JsonRequestBehavior.AllowGet);
}

Why does my button click execute multiple times?

I have written this ajax code to send data to web service asmx. It works but with a single click, it inserts data multiple times and sometimes it takes 2,3 click to insert data.
.js
<script type="text/javascript">
function save()
{
$("button").click
(
function()
{
$.post
(
"http://localhost:82/ws/himher.asmx/InsertUsers",
{name: txtUserName.value, pwd: txtUserPwd.value},
//
);
}
);
}
</script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<label>User Name</label>
<input id="txtUserName" type="text" class="form-control" />
</div>
</div>
<div class="row">
<div class="col-md-12">
<label>Password</label>
<input id="txtUserPwd" type="text" class="form-control" />
</div>
</div>
<br/>
<div class="row">
<div class="col-md-12">
<button type="submit" onclick='save()' class="btn btn-primary pull-right">Register</button>
</div>
</div>
</div>
.cs:
public class himher : System.Web.Services.WebService
{
[WebMethod(EnableSession = true)]
//[ScriptMethod(UseHttpGet = false)]
public string InsertUsers(string name, string pwd)
{
try
{
basicoperation bop = new basicoperation();
return bop.insertUsers(name, pwd);
}
catch (Exception ex)
{
throw ex;
}
}
public string insertUsers(string Name, string Password)
{
string status;
String ConStr = ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
SqlConnection sqlCon = new SqlConnection(ConStr); // to make a connection with DB
SqlCommand sqlCom = new SqlCommand("InsertUsers", sqlCon); // now in order to perform action such as insert SP, we must create command object which needs command name and conncetion only
sqlCom.CommandType = CommandType.StoredProcedure; // you must tell the system that insertInfo is a storedprocedure
SqlParameter sqlParamName = new SqlParameter("#UserName", Name);
SqlParameter sqlParamPwd= new SqlParameter("#Password", Password);
sqlCom.Parameters.Add(sqlParamName);
sqlCom.Parameters.Add(sqlParamPwd);
try
{
sqlCon.Open();
int i= sqlCom.ExecuteNonQuery(); // executenonquery is used for INSERT, UPDATE, DELETE
//sqlCom.ExecuteScalar(); // used to pick or read a single value from procedure
// Response.Write("Done");
sqlCon.Close();
status= "Success";
}
catch (Exception ex)
{
//response.Write(ex.Message);
status = ex.Message;
}
return status;
}
}
You have two bindings to a saving function, one of them is binded when you click on your button. Rewrite your JS like this:
<script type="text/javascript">
function save()
{
$.post(
"http://localhost:82/ws/himher.asmx/InsertUsers",
{name: txtUserName.value, pwd: txtUserPwd.value}
);
}
</script>
This way your save function will do only saving logic. Binding to call this function is done in HTML by <button type="submit" onclick='save()'>.
If you're going to release this code to users you really need to implement some duplicate action prevention rather than hope they just click it once. Ergo while you may find out why it insets multiples, you cannot rely on user behaviour to keep trash out of the database; they will hit a go slow and hammer that button in frustration. Even if you disable the button, they'll refresh and submit again. Dedupe your data before you insert - this is multi layer information security; even if they disable the script that stops them hammering the button, you don't accept the duplicates
Note, I don't offer this as a solution to a genuine "I click this once and 3 data are inserted" - fix that bug sure, but control the user behaviour with regards to your desire for data purity, within the server (where you're in total control)

How to invoke my post method when I'm changing dropdown list in ASP.NET MVC

I'm very new to MVC and Javascript so please be patient with me, I'm working on small application and I came to part when I need to select something from dropdown list and based on that selection I need to redirect user to another View, I also need to determine somehow where I should redirect user, so that is reason why I tried to pass parameter also ( database ID to my post method) but unfortunatelly this is not working, in section below I will post my code:
Method which is sending data to my DropDownList :
public ActionResult ShowArticleGroup()
{
List<ArticleGroup> articlesGroups = GroupsController.GetAllGroups();
ViewBag.articlesGroups = articlesGroups;
return View(articlesGroups);
}
[HttpPost]
public ActionResult ShowArticleGroup(string id)
{
//Here I wanted to take ID of selected Group and because there will be allways 3 Groups I can do if else and Redirect by ID
if(id =="00000000-0000-0000-0000-000000000002")
{
return RedirectToAction("Create","Article");
}
return RedirectToAction("Create", "Article");
}
And my VIEW - there is only one control on the view : just one dropdown, and based on selection I should be redirected to another view, and I wanted here to take ID of selected group and by that I wanted to redirect user to appropiate view:
#model IEnumerable<Model.ArticleGroup>
#{
ViewBag.Title = "Add new article";
}
<h3 style="text-align:center">Choose article group</h3>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true)
<div class="form-group" style="text-align:center">
#Html.DropDownList("Group", new SelectList(ViewBag.articlesGroups, "GroupID", "GroupTitle.Name"), null, new { onchange = "document.location.href = '/Articles/ShowArticleGroup/' + this.options[this.selectedIndex].value;" })
</div>
</div>
}
First of all, usage of location.href on DropDownList seems wrong here:
#Html.DropDownList("Group", new SelectList(ViewBag.articlesGroups, "GroupID", "GroupTitle.Name"), null,
new { onchange = "document.location.href = '/Articles/ShowArticleGroup/' + this.options[this.selectedIndex].value;" })
AFAIK, location.href used for redirect to another page using HTTP GET, hence it will try to call first ShowArticleGroup action method without parameter, and the URL parameter simply ignored since given URL parameter only exist in POST.
To submit the form with DropDownList, you need to handle change event triggering POST into controller action method:
jQuery
<script type="text/javascript">
$(document).ready(function() {
$("#Group").change(function() {
var groupId = $("#Group").val();
$.post('#Url.Action("ShowArticleGroup", "ControllerName")', { id: groupId }, function (response, status) {
// response handling (optional)
});
});
});
</script>
DropDownList
#Html.DropDownList("Group", new SelectList(ViewBag.articlesGroups, "GroupID", "GroupTitle.Name"), null)
I recommend you using strongly-typed DropDownListFor with binding to a viewmodel approach if you want to pass viewmodel contents during form submit.
NB: $.post is shorthand version of $.ajax which uses POST submit method as default.
Related issues:
Autopost back in mvc drop down list
MVC 4 postback on Dropdownlist change

Form with JQuery Steps using aui:form tag in Liferay submits no data

I built a portlet and added a entity named Idea. There are two JSPs, one is the view and one the edit.
In the view there is only a button to create a new Idea and a table showing all ideas. Clicking on the button shows the edit jsp.
There is a form with two fieldsets and input stuff.
The "problem" is i cannot use the <aui:form ... stuff because it won't work with JQuery steps (or better, i cannot get it working). So i am using normal tag and also JQuery steps is providing the submit button which is only a <a href="#finish" ...>. So that wont bring the form to submit and the data being in the database.
So I tried to do it within the javascript code of the definition of jquery steps like here:
$(document).ready(function(){
var form = $("#wizard").show();
form.steps(
{
headerTag : "h3",
bodyTag : "fieldset",
transitionEffect : "slideLeft",
onFinishing: function (event, currentIndex) {
alert("Submitted!");
var data = jQuery("#wizard").serialize();
alert(data);
jQuery("#wizard").submit();
form.submit();[/b]
},
onFinished: function (event, currentIndex) {
//I tried also here..
},
});
});
But even if i declare the data explicitely it wont put it in the db.
So my idea was that the "controller" class which calls the "addIdea" function is never called.
How am I solving the problem?
Here is also my jsp code for the form part:
<aui:form id="wizard" class="wizard" action="<%= editIdeaURL %>" method="POST" name="fm">
<h3>Idea</h3>
<aui:fieldset>
<aui:input name="redirect" type="hidden" value="<%= redirect %>" />
<aui:input name="ideaId" type="hidden" value='<%= idea == null ? "" : idea.getIdeaId() %>'/>
<aui:input name="ideaName" />
</aui:fieldset>
<h3>Idea desc</h3>
<aui:fieldset>
<aui:input name="ideaDescription" />
</aui:fieldset>
<aui:button-row>
<aui:button type="submit" />
<aui:button onClick="<%= viewIdeaURL %>" type="cancel" />
</aui:button-row>
</aui:form>
Is there a way to "teach" JQuery Steps the <aui:*** tags? I tried it already while initializing the form but it won't work. To get it working using the aui tags would be great. Because otherwise the Liferay portal wont get the data or it would get it only with hacks right?
€dit: What I forgot, when I submit the form using javascript submit, it creates a new dataentry in the db but no actual data in it.
€dit2:
The editIdeaURL is referenced a bit over the form here:
<portlet:actionURL name='<%=idea == null ? "addIdea" : "updateIdea"%>'
var="editIdeaURL" windowState="normal" />
and the addIdea code looks as follows:
In the IdeaCreation class first this:
public void addIdea(ActionRequest request, ActionResponse response)
throws Exception {
_updateIdea(request);
sendRedirect(request, response);
}
Where _updateIdea() is:
private Idea _updateIdea(ActionRequest request)
throws PortalException, SystemException {
long ideaId = (ParamUtil.getLong(request, "ideaId"));
String ideaName = (ParamUtil.getString(request, "ideaName"));
String ideaDescription = (ParamUtil.getString(request, "ideaDescription"));
ServiceContext serviceContext = ServiceContextFactory.getInstance(
Idea.class.getName(), request);
Idea idea = null;
if (ideaId <= 0) {
idea = IdeaLocalServiceUtil.addIdea(
serviceContext.getUserId(),
serviceContext.getScopeGroupId(), ideaName, ideaDescription,
serviceContext);
} else {
idea = IdeaLocalServiceUtil.getIdea(ideaId);
idea = IdeaLocalServiceUtil.updateIdea(
serviceContext.getUserId(), ideaId, ideaName, ideaDescription,
serviceContext);
}
return idea;
}
And to finally put the data using IdeaLocalServiceImpl:
public Idea addIdea(
long userId, long groupId, String ideaName, String ideaDescription,
ServiceContext serviceContext)
throws PortalException, SystemException {
User user = userPersistence.findByPrimaryKey(userId);
Date now = new Date();
long ideaId =
counterLocalService.increment(Idea.class.getName());
Idea idea = ideaPersistence.create(ideaId);
idea.setIdeaName(ideaName);
idea.setIdeaDescription(ideaDescription);
idea.setGroupId(groupId);
idea.setCompanyId(user.getCompanyId());
idea.setUserId(user.getUserId());
idea.setCreateDate(serviceContext.getCreateDate(now));
idea.setModifiedDate(serviceContext.getModifiedDate(now));
super.addIdea(idea);
return idea;
}
Any ideas?

Categories