Here is my JQGrid Code:
click: function (e) {
debugger;
var id = $(e.target).closest("tr.jqgrow").attr("id");
rowdata = jQuery("#EmpTable").getRowData(id);
Data = { Id: rowdata.Id, Name: rowdata.Name, Designation: rowdata.Designation };
var url = 'http://localhost:50428/Script/Edit/';
return $.post(url, Data);
}
here is my controller code where the data is collecting
[HttpPost]
public ActionResult Edit(FormCollection form)
{
gridmodel properties = new gridmodel();
properties.Id = Convert.ToInt32(form["id"]);
properties.Name = form["Name"];
properties.Designation = form["Designation"];
ViewBag.id = properties.Id;
ViewBag.name = properties.Name;
ViewBag.designation = properties.Designation;
return View();
}
Now here is my View code
the data that is passing from the controller to the view
#model MVC5_JQGrid.Models.gridmodel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Edit</title>
</head>
<body>
<div>
Id:#ViewBag.id
<br />
Name:#ViewBag.name
<br />
Designation:#ViewBag.designation
</div>
</body>
</html>
But i am unable to load this page but in network ---> Response body i can see that these values are assigned
Update
Hello Venkata thanks for the answer i will keep the points which you mentioned and +1 from my side for the observation ,coming to the problem. it was resolved from oleg suggestion:(Here is the answer given by Oleg) The reason of your problem is the usage of $.post(url, Data); which just send data with respect of $.ajax({url: "/Script/Edit", data: Data, type: "POST"});. You need to do $.submit instead. If you would use HTTP GET then you can just assign new URL which includes parameters to location.href (something like location.href = "/Script/Edit?" + $.param(Data)). In case of HTTP POST one need to build with elements which contains (or just have on the page hidden form with all required elements with required name attributes) and use $.submit.
Thanks for the help from oleg and Venkata
Few Changes required in your code:
Observation and Notes:
Before fixing, we should know few points here regarding architecture, control-flow and standards
jQuery AJAX requests get response to its success callback handler(in your code you've missed success call)
In success function We should build or append or set HTML to target placeholder tag in existing page (let us say you have div for Edit section like <div id='editSection'>...</div> in your jqGrid page. you should bind the responseView to editSection div)
When we send AJAX request: In Controller.Action Instead of return View(); we should have return PartialView();
In your view.cshtml give preference to bind elements with Model rather than ViewData. You can get model to view if you do return PartialView(model); in the Action.
Try to reduce usage of ViewData or ViewBag in view.cshtml. Also business logic not recommended in Views.
Try to Follow best practices: Capitalization Conventions (in your code change gridmodel class name to GridModel)
By default routing url template will have {controller}/{action} (from your url Script is controller and Edit is action)
Make sure that you're passing correct Controller and Action names (Is Edit action located in the Controller with name ScriptController?)
Changes in JavaScript JQGrid Code:
url = '/Script/Edit/';
return $.post(url, Data).success(function(response){
//response datatype can be JSON or XML or HTML or text (In your case HTML Edit.cshtml View)
//update you target html tag with response view.
$('#editSection').html(responseView);
});
Changes in Controller:
[HttpPost]
public ActionResult Edit(FormCollection form)
{
var properties = new gridmodel();
properties.Id = Convert.ToInt32(form["id"]);
properties.Name = form["Name"];
properties.Designation = form["Designation"];
ViewBag.id = properties.Id;
ViewBag.name = properties.Name;
ViewBag.designation = properties.Designation;
return PartialView();
}
You can change above Edit Action like below if action require input parameters only id, name & designation
[HttpPost]
public ActionResult Edit(int id, string name, string designation)
{
var gridModel = new GridModel();
gridModel.Id = id;
gridModel.Name = name;
gridModel.Designation = designation;
ViewBag.id = gridModel.Id;
ViewBag.name = gridModel.Name;
ViewBag.designation = gridModel.Designation;
return PartialView(gridModel);
}
Hello Venkata thanks for the answer i will keep the points which you mentioned and +1 from my side for the observation ,coming to the problem. it was resolved from oleg suggestion:(Here is the answer given by Oleg) The reason of your problem is the usage of $.post(url, Data); which just send data with respect of $.ajax({url: "/Script/Edit", data: Data, type: "POST"});. You need to do $.submit instead. If you would use HTTP GET then you can just assign new URL which includes parameters to location.href (something like location.href = "/Script/Edit?" + $.param(Data)). In case of HTTP POST one need to build with elements which contains (or just have on the page hidden form with all required elements with required name attributes) and use $.submit. Thanks for the help from oleg and Venkata
Related
I request a ajax call from the View Index.cshtml to an action method in HomeController.cs and get json data that I use in Index.cshtml.
Another View Display.cshtml is called using Url.Action() from different anchor tags in Index.cshtml.Depending on the anchor tag clicked, the data will be displayed in Display.cshtml.
Now I have a requirement where the same json(used in Index.cshtml) is needed in Display.cshtml.
Please let me know the best way to pass the json data with minimal calls to server & data storage on client side.
Thank you.
Ajax call in Index.cshtml
$(document).ready(function () {
$.getJSON("#Url.Action("GetJsonData", "Home")", function (json) { ... }
Anchor tag in Index.cshtml
<a href="#Url.Action("Display", "Home", new { Name = "Test" })">
Call Display.cshtml in HomeController.cs
public ActionResult Display(string Name)
{
ViewBag.Name = Name;
return View();
}
I want to send a message to userID=3 by going to /MyController/Message/3
This executes Message() [get] action, I enter some text in the text area and click on Save to post the form
Message() [post] action saves the changes, resets the value of SomeText to empty string and returns to the view.
At this point I expect the text area to be empty because I have set ViewData["SomeText"] to string.Empty.
Why is text area value not updated to empty string after post action?
Here are the actions:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Message(int ID)
{
ViewData["ID"] = ID;
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
// save Text to database
SaveToDB(ID, SomeText);
// set the value of SomeText to empty and return to view
ViewData["SomeText"] = string.Empty;
return View();
}
And the corresponding view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm())
{ %>
<%= Html.Hidden("ID", ViewData["ID"])%>
<label for="SomeText">SomeText:</label>
<%= Html.TextArea("SomeText", ViewData["SomeText"]) %>
<input type="submit" value="Save" />
<% } %>
</asp:Content>
The problem is that your ModelState is re-filled with the posted values.
What you can do is clear it on the Action that has the Post attribute :
ModelState.Clear();
The problem is the HtmlHelper is retrieving the ModelState value, which is filled with the posted data. Rather than hacking round this by resetting the ModelState, why not redirect back to the [get] action. The [post] action could also set a temporary status message like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
// save Text to database
SaveToDB(ID, SomeText);
TempData["message"] = "Message sent";
return RedirectToAction("Message");
}
This seems to me like more correct behaviour.
The html helpers read the value from the ModelState. And there's no elegant way to override this behaviour.
But if you add this line after SaveToDB(ID, SomeText), it should work :
ModelState["SomeText"].Value =
new ValueProviderResult("", "", CultureInfo.CurrentCulture);
I tried everything, but only worked when I did something like this:
ModelState.Clear();
//This will clear the address that was submited
viewModel.Address = new Address();
viewModel.Message = "Dados salvos com sucesso!";
return View("Addresses", ReturnViewModel(viewModel));
Hope this helps.
Instead of using ModelState.Clear() which clears the whole modelstate, you can do ModelState.Remove("SomeText"), if you want to. Or render the Input without the htmlhelper-extensions.
They are designed to take the Value from ModelState instead of the Model (or viewdata).
That is a clientside behavior. I would recommend using javascript. If you use JQuery, you can do it like this:
<script type="text/javascript">
$(function(){ $("#SomeText").val("");});
</script>
I don't use Javascript anymore, but I believe in regular JS that it is like:
document.getElementById("SomeText").value = "";
(You would do this on one of the load events.
<body onload="...">
Hope this helps.
I am fairly certain the textarea is grabbing the value from the Request.Form under the hood since ViewData["SomeText"] is empty.
Is it possible that the model state has been updated with an error? I believe that it will pull the attempted value from the model state rather than from view data or the model if the model state isn't valid.
EDIT:
I'm including the relevant section of the source code from the TextArea HtmlHelper extension below. It appears to me that it does exactly what I expected -- if there has been a model error, it pulls the value from the model state, otherwise it uses it from ViewData. Note that in your Post method the "SomeText" key shouldn't even exist until you set it, i.e., it won't be carried forward from the version of the code that responds to the GET.
Since you explicitly supply a value to the ViewData, useViewData should be false, attemptedValue should be false unless an error has been set in the model state.
// If there are any errors for a named field, we add the css attribute.
ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(name, out modelState)) {
if (modelState.Errors.Count > 0) {
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
}
// The first newline is always trimmed when a TextArea is rendered, so we add an extra one
// in case the value being rendered is something like "\r\nHello".
// The attempted value receives precedence over the explicitly supplied value parameter.
string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
tagBuilder.SetInnerText(Environment.NewLine + (attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : value)));
return tagBuilder.ToString(TagRenderMode.Normal);
Do s.th. like this:
add:
ModelState.Clear();
before the return statement of the submit buttons action method. Works for me. It could work for you.
I am trying to set up a simple login html page, whose action is sent to mvc controller on another of my sites. I have no problem setting up the page to do the post, and in the mvc controller I have my method that reads the form post. The problem is that I am not seeing my fields from the html form in the form collection.
Is there something special that I need to do to read a form post within a mvc controller method, if so what is that?
The is the form action markup from my page
<form action="http://reconciliation-local.sidw.com/login/launch" method="post">
User Name <input type="text" id="username"/><br/>
Password <input type="text" id="password"/>
<input type="submit" value="launch"/>
</form>
The controller method
[HttpPost]
public ActionResult launch(FormCollection fc)
{
foreach (string fd in fc)
{
ViewData[fd] = fc[fd];
}
return View();
}
When I step through the controller method code, I am not seeing anything in the formcollection parameter.
Post Html To MVC Controller
Create HTML page with form (don't forget to reference a Jquery.js)
<form id="myform" action="rec/recieveData" method="post">
User Name <input type="text" id="username" name="UserName" /><br />
Password <input type="text" id="password" name="Password"/>
<input type="submit" id="btn1" value="send" />
</form>
<script>
$(document).ready(function () {
//get button by ID
$('#btn1').submit(function () {
//call a function with parameters
$.ajax({
url: 'rec/recieveData', //(rec)= Controller's-name
//(recieveData) = Action's method name
type: 'POST',
timeout: '12000', (optional 12 seconds)
datatype: 'text',
data: {
//Get the input from Document Object Model
//by their ID
username: myform.username.value,
password: myform.password.value,
}
});
});
});
</script>
Then in The MVC Controller
controller/action
| |
1. Create Controller named rec (rec/recieveData)
Create View named rec.cshtml
Here is the controller:
public class recController : Controller
{
// GET: rec
string firstname = "";
string lastname = "";
List<string> myList = new List<string>();
public ActionResult recieveData(FormCollection fc)
{
//Recieve a posted form's values from parameter fc
firstname = fc[0].ToString(); //user
lastname = fc[1].ToString(); //pass
//optional: add these values to List
myList.Add(firstname);
myList.Add(lastname);
//Importan:
//These 2 values will be return with the below view
//using ViewData[""]object...
ViewData["Username"] = myList[0];
ViewData["Password"] = myList[1];
//let's Invoke view named rec.cshtml
// Optionaly we will pass myList to the view
// as object-model parameter, it will still work without it thought
return View("rec",myList);
}
}
Here is the View:
#{
ViewBag.Title = "rec";
}
<h2>Hello from server</h2>
<div>
#ViewData["Username"]<br /> <!--will display a username-->
#ViewData["Password"] <!-- will display a password-->
</div>
If you posted some code it would be much easier to help you, so please edit your question...
Make sure that your form's action has the correct address, that your method is specifying POST (method="POST") and that the input fields under your form have name attributes specified.
On the server side, try making your only parameter a FormCollection and test that the fields in your form posted through the debugger. Perhaps your model binding isn't correct and the FormCollection will at least show you what got posted, if anything.
These are just common issues I've seen. Your problem could be different, but we need to see what you're working with to be able to tell.
Try something like this:
cQuery _aRec = new cQuery();
_aRec.Sqlstring = "SELECT * FROM Admins";
DataSet aDS = _aRec.SelectStatement();
DataTable aDT = aDS.Tables[0];
foreach (DataRow aDR in aDT.Rows){
if (txtAdminUsername.Text == aDR[0].ToString()){
if (txtAdminPassword.Text == aDR[1].ToString()){
Session["adminId"] = aDR[0];
Response.Redirect("Admin.aspx");
return;
}
}
}
Make sure that your FormCollection object properties for username and password are defined properly.
I had to use the name attribute on the text tag, and that solved my problem, is now working like a charm.
You have to use Ajax to do that.. Whenever you want to "submit" from client side, you should use Ajax to update the server
Step 1 - you redirect your Ajax call to your action, but with your list of parameters in the query-string appended
$.ajax(url: url + "?" + your_query_string_parameter_list_you_want_to_pass)
Step 2 - add optional parameters to your Controller-action with the same names and types you expect to get returned by the client
public ActionResult MyControllerAjaxResponseMethod(type1 para1 = null,
type2 para2 = null,
type3 para3 = null, ..)
Know that the optional parameters have to be initialized, otherwise the Action itself will always ask for those
Here's where the "magic" happens though --> MVC will automatically convert the query-string parameters into your optional controller-parameters if they match by name
I was also looking for a good answer for this, --> i.e. - one that doesn't use q-s for that usage, but couldn't find one..
Kinda makes sense you can't do it in any other way except by the url though..
This may seem strange, but I would like to have my model contain Json data, which I could then use javascript to render html with the contents. My code looks like the following -
My Controller -
public ActionResult Index()
{
Object myObject = FillMyObjectWithData();
string json = new JavaScriptSerializer().Serialize(myObject);
return View(json);
}
My View -
#model string /*Json data will be in the model*/
<div>
//standard html in here
</div>
<script>
$(document).ready(function() {
doCoolStuff(#Model);
});
</script>
I am getting the error - "Illegal characters in path."
What is the correct way to accomplish this?
The problem is in return View(json);
You are getting the wrong function overload View(string), that is the overload to get a view by name. Try:
return View((object)json);
Also you want the raw JSON without HTML encoding:
doCoolStuff(#Html.Raw(#Model));
Try:
#model string /*Json data will be in the model*/
<div>
//standard html in here
</div>
<script>
$(document).ready(function() {
var temp = #model;
doCoolStuff(temp);
});
</script>
What is your motivation for attempting it this way? If you really want to return json you may be better served making an ajax request after the view/page loads and using javascript/jquery to render your UI with. This would be a good candidate for KnockoutJS.
I want to send a message to userID=3 by going to /MyController/Message/3
This executes Message() [get] action, I enter some text in the text area and click on Save to post the form
Message() [post] action saves the changes, resets the value of SomeText to empty string and returns to the view.
At this point I expect the text area to be empty because I have set ViewData["SomeText"] to string.Empty.
Why is text area value not updated to empty string after post action?
Here are the actions:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Message(int ID)
{
ViewData["ID"] = ID;
return View();
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
// save Text to database
SaveToDB(ID, SomeText);
// set the value of SomeText to empty and return to view
ViewData["SomeText"] = string.Empty;
return View();
}
And the corresponding view:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm())
{ %>
<%= Html.Hidden("ID", ViewData["ID"])%>
<label for="SomeText">SomeText:</label>
<%= Html.TextArea("SomeText", ViewData["SomeText"]) %>
<input type="submit" value="Save" />
<% } %>
</asp:Content>
The problem is that your ModelState is re-filled with the posted values.
What you can do is clear it on the Action that has the Post attribute :
ModelState.Clear();
The problem is the HtmlHelper is retrieving the ModelState value, which is filled with the posted data. Rather than hacking round this by resetting the ModelState, why not redirect back to the [get] action. The [post] action could also set a temporary status message like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Message(int ID, string SomeText)
{
// save Text to database
SaveToDB(ID, SomeText);
TempData["message"] = "Message sent";
return RedirectToAction("Message");
}
This seems to me like more correct behaviour.
The html helpers read the value from the ModelState. And there's no elegant way to override this behaviour.
But if you add this line after SaveToDB(ID, SomeText), it should work :
ModelState["SomeText"].Value =
new ValueProviderResult("", "", CultureInfo.CurrentCulture);
I tried everything, but only worked when I did something like this:
ModelState.Clear();
//This will clear the address that was submited
viewModel.Address = new Address();
viewModel.Message = "Dados salvos com sucesso!";
return View("Addresses", ReturnViewModel(viewModel));
Hope this helps.
Instead of using ModelState.Clear() which clears the whole modelstate, you can do ModelState.Remove("SomeText"), if you want to. Or render the Input without the htmlhelper-extensions.
They are designed to take the Value from ModelState instead of the Model (or viewdata).
That is a clientside behavior. I would recommend using javascript. If you use JQuery, you can do it like this:
<script type="text/javascript">
$(function(){ $("#SomeText").val("");});
</script>
I don't use Javascript anymore, but I believe in regular JS that it is like:
document.getElementById("SomeText").value = "";
(You would do this on one of the load events.
<body onload="...">
Hope this helps.
I am fairly certain the textarea is grabbing the value from the Request.Form under the hood since ViewData["SomeText"] is empty.
Is it possible that the model state has been updated with an error? I believe that it will pull the attempted value from the model state rather than from view data or the model if the model state isn't valid.
EDIT:
I'm including the relevant section of the source code from the TextArea HtmlHelper extension below. It appears to me that it does exactly what I expected -- if there has been a model error, it pulls the value from the model state, otherwise it uses it from ViewData. Note that in your Post method the "SomeText" key shouldn't even exist until you set it, i.e., it won't be carried forward from the version of the code that responds to the GET.
Since you explicitly supply a value to the ViewData, useViewData should be false, attemptedValue should be false unless an error has been set in the model state.
// If there are any errors for a named field, we add the css attribute.
ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(name, out modelState)) {
if (modelState.Errors.Count > 0) {
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
}
// The first newline is always trimmed when a TextArea is rendered, so we add an extra one
// in case the value being rendered is something like "\r\nHello".
// The attempted value receives precedence over the explicitly supplied value parameter.
string attemptedValue = (string)htmlHelper.GetModelStateValue(name, typeof(string));
tagBuilder.SetInnerText(Environment.NewLine + (attemptedValue ?? ((useViewData) ? htmlHelper.EvalString(name) : value)));
return tagBuilder.ToString(TagRenderMode.Normal);
Do s.th. like this:
add:
ModelState.Clear();
before the return statement of the submit buttons action method. Works for me. It could work for you.