The question here is very simple
This is my view
<%# Control Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<GetmoreRevamp.BAL.Product>" %>
<link href="<%=Url.Content("~/Content/AddToCart.css")%>" rel="stylesheet"
type="text/css" />
<link href="<%=Url.Content("~/Scripts/jquery-1.4.1.js")%>" type="text/javascript" />
<script type="text/javascript">
function submitForm(formData) {
var tdata = $(formData).serialize();
$.ajax({
type: "POST",
url: '<%= Url.Action("AddToCart","Cart")%>',
data: tdata,
contentType: 'application/json; charset=utf-8',
datatype: "json",
success: function(result) { success(result); }
});
return false;
}
function success(result) {
alert("success:" + result.success);
}
</script>
<% using (Html.BeginForm("AddToCart", "Cart ", Model, FormMethod.Post,
new { onsubmit = "return submitForm('this');" })) {%>
<div class="prishosbtn">
<a rel="prettyPhoto" href="" id="buy">
<%Response.Write("<input type=\"image\" class=\"imgClass\" alt=\"" +
(Model != null && Model.ProductName != null ?
Model.ProductName : "KOEB") + "\" src=\"" +
Url.Content("~/pics/undersider/listevisning/kob-knap.png") +
"\" id=\"ImageButton\" name=\"ImageButton\" />");%>
</a>
</div>
<%}%>
This is my controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using GetmoreRevamp.WEB.Models;
using GetmoreRevamp.WEB.Models.BLLModels;
using System.Web.Security;
using System.Security.Principal;
using GetmoreRevamp.WEB.Utilities;
using GetmoreRevamp.BAL;
namespace GetmoreRevamp.WEB.Controllers
{
public class CartController : Controller
{
//
// GET: /Cart/
public ActionResult Index()
{
return View("Cart");
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddToCart(Product product)
{
JsonResult result = new JsonResult();
OrderHeader orderHeader =
Session[Constants.CurrentlySessionOrderHeader] as OrderHeader;
if (orderHeader == null)
{
orderHeader = new OrderHeader();
}
if (product != null && product.ProductGuid != null &&
string.Equals(product.ProductGuid, string.Empty))
{
orderHeader.AddOrderLineItem(1, product);
orderHeader.Calculate();
Session[Constants.CurrentlySessionOrderHeader] = orderHeader;
//Default redirection Must be changed when actual view is created
result.Data = true;
}
else
{
//Default redirection Must be changed when actual view is created
result.Data = false;
}
return result;
}
}
}
"Product" is defined in bal. Product contains other business entities. What i simply want to do is to access the model with which view is binded in jquery and then post it to my action method in cart controller. i do not want to post the id of product. I want to post the actual model via jquery to my action method. I am a total newbie in this. so any help and most imp simple solution will be preferred
MVC matches field names to the business object in the action method, so if Product has a ProductID field, there should be a:
Html.TextBox("ProductID")
declaration, or use the TextBoxFor method in MVC 2. I'm pretty sure that's still how it works even when posting using JQuery. The model binder handles the process of taking the form fields and passing them to the product object. But, all of the fields have to be within the form that you are posting to the server, or you have to explicitly pass the parameters where you pass the tdata variable...
HTH.
Related
I am trying to use an Ajax (I think) call to update my model value and then have that new value reflected in the view. I am just using this for testing purposes for the moment.
Here's the overview:
MODEL
public class MyModel
{
public int Integer { get; set; }
public string Str { get; set; }
}
CONTROLLER
public ActionResult Index()
{
var m = new MyModel();
return View("Test1", m);
}
[HttpPost]
public ActionResult ChangeTheValue(MyModel model)
{
var m = new MyModel();
m.Str = model.Str;
m.Str = m.Str + " Changed! ";
m.Integer++;
return View("Test1", m);
}
VIEW
#model Test_Telerik_MVC.Models.MyModel
#using Test_Telerik_MVC.Models
#{
ViewBag.Title = "Test1";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
Test1</h2>
#if (false)
{
<script src="~/Scripts/jquery-1.4.4.min.js" type="text/javascript"></script>
<script src="~/Scripts/jquery-ui.min.js" type="text/javascript"></script>
}
<h2>
ViewPage1
</h2>
<div>
<input type="button" onclick="changeButtonClicked()" id="changeButton" value="Click Me!" />
<input type="text" value="#Model.Str" class="txt" id="str" name="Str"/>
<div></div>
</div>
<script type="text/javascript">
function changeButtonClicked() {
var url = '#Url.Action("ChangeTheValue", "Test1")';
var data = '#Model';
$.post(url, data, function (view) {
$("#Str").value = '#Model.Str';
});
}
</script>
Basically the view renders a button with a textbox. My sole aim is to simply display the value of my model (Str property) in the textbox.
I have tried various combinations of the changeButtonClicked() function to no avail. Test1 is the name of my controller. What I don't understand is when I debug it, the controller action fires and sets my values correctly. If I place a breakpoint on the "#Model.Str" section of the input tag, it shows me that my #Model.Str is equal to Changed! which is correct. However, as soon as my success function fires in the javascript, the value reverts back to it's original value.
I can make it work by changing the input type to submit and wrapping it in a #Html.BeginForm() section but I am wondering if/how to do it like this? Or is a Submit the only way to accomplish it?
Thanks
First thing in the jQuery the proper way to set a value of an input is to use:
$("#Str").val(#Model.Str);
Next we'll look at the controller. In the POST action result you are returning the entire View in your AJAX call. That means all the HTML, script references, and JavaScript are being returned in your jQuery post request. Since all you are trying to update is the value of the input named Str, I would just return that value as JSON and nothing else.
[HttpPost]
public ActionResult ChangeTheValue(MyModel model)
{
var m = new MyModel();
m.Str = model.Str;
m.Str = m.Str + " Changed! ";
m.Integer++;
return Json(m.Str);
}
Next I would place your HTML inputs in a <form> so you can have jQuery serialize your model for you and then you can change your jQuery post code to be:
function changeButtonClicked() {
var url = '#Url.Action("ChangeTheValue", "Test1")';
$.post(url, $('form').serialize(), function (view) {
$("#Str").val(view);
});
}
All the serialization is doing is encoding the inputs in your form into a string and if everything is named properly ASP.NET will bind that back to your model.
If you need to have your route handle both AJAX calls and full requests you could use ASP.NET's IsAjaxRequest function to test the request and return different results depending on if the request is AJAX or not. You would do something like this in your controller:
[HttpPost]
public ActionResult ChangeTheValue(MyModel model)
{
var m = new MyModel();
m.Str = model.Str;
m.Str = m.Str + " Changed! ";
m.Integer++;
if (Request.IsAjaxRequest) {
return Json(m.Str);
}
else {
return View("Test1", m);
}
}
In the ActionResult above you are doing everything you did before, but now are testing the request type and if it's AJAX you return a JSON result of your string value. If the request was not from an AJAX call then the full View (HTML, scripts, etc) are returned to be displayed in the browser.
I hope this is helps you out and is what you were looking for.
You can update the view, just not the model. The model in a razor page is compiled on the server in order to render the view; you would need to recompile the razor page after every ajax request.
Only real option is to return json from server and manually update DOM/View.
Is there a way to load ascx file by jQuery?
UPDATE:
thanks to #Emmett and #Yads. I'm using a handler with the following jQuery ajax code:
jQuery.ajax({
type: "POST", //GET
url: "Foo.ashx",
data: '{}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response)
{
jQuery('#controlload').append(response.d); // or response
},
error: function ()
{
jQuery('#controlload').append('error');
}
});
but I get an error. Is my code wrong?
Another Update :
I am using
error: function (xhr, ajaxOptions, thrownError)
{
jQuery('#controlload').append(thrownError);
}
and this is what i get :
Invalid JSON:
Test =>(this test is label inside my ascx)
and my ascx file after Error!!!
Another Update :
my ascx file is somthing like this:
<asp:DropDownList ID="ddl" runat="server" AutoPostBack="true">
<asp:ListItem>1</asp:ListItem>
<asp:ListItem>2</asp:ListItem>
</asp:DropDownList>
<asp:Label ID="Label1" runat="server">Test</asp:Label>
but when calling ajax i get this error in asp: :(
Control 'ctl00_ddl' of type 'DropDownList' must be placed inside a form tag with runat=server.
thanks to #Yads. but his solution only work with html tag.
Building off Emmett's solution
public class FooHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/html";
context.Response.Write(RenderPartialToString("Foo.ascx"));
}
private string RenderPartialToString(string controlName)
{
Page page = new Page();
Control control = page.LoadControl(controlName);
page.Controls.Add(control);
StringWriter writer = new StringWriter();
HttpContext.Current.Server.Execute(page, writer, false);
return writer.ToString();
}
public bool IsReusable
{
get
{
return false;
}
}
}
Use the following jquery request
jQuery.ajax({
type: "POST", //GET
url: "Foo.ashx",
dataType: "html",
success: function (response)
{
jQuery('#controlload').append(response); // or response
},
error: function ()
{
jQuery('#controlload').append('error');
}
});
public ActionResult Foo()
{
return new ContentResult
{
Content = RenderPartialToString("Foo.ascx", null),
ContentType = "text/html"
};
}
//http://www.klopfenstein.net/lorenz.aspx/render-partial-view-to-string-asp-net-mvc-benchmark
public static string RenderPartialToString(string controlName, ViewDataDictionary viewData)
{
ViewPage vp = new ViewPage();
vp.ViewData = viewData;
Control control = vp.LoadControl(controlName);
vp.Controls.Add(control);
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
vp.RenderControl(tw);
}
}
return sb.ToString();
}
*.ascx files are rendered on the server side (inside of an *.aspx page), not the client side (where JavaScript is executed).
One option might be to create a blank *.aspx, put the user control on the *.aspx page, and then get that page via jQuery and dump the result on the page.
Edit
Based on your comment, I have another suggestion:
If you're developing a CMS style application, you should build your *.ascx controls so that they are compatible with the ASP.NET AJAX Toolkit. That will allow the users to add content to the page without doing a full refresh.
If you really want to make things nice for the user, you should check out Web Parts and ASP.NET AJAX as Web Parts were really designed so that users could customize the content on their pages.
I'm new in ASP.NET MVC so the question could appear 'stupid', sorry.
I have a Partial View inside my Home view.
The Partial View submit a form calling an Action Method inside the HomeController.
It works fine with server validation, the problem is that after the post only the Partial View is rendered.
How can I render the entire Home view after post?
About the code:
Inside PartialView I have a form:
<% using (Html.BeginForm("Request", "Home")) { %>
Request is a ActionResult defined inside my HomeController.
[HttpPost]
public ActionResult Request(RequestModel model)
{
if (ModelState.IsValid)
{
// Saving data .....
}
else
{
// Show Server Validation Errors
return View();
}
}
At this time, after the post, the ascx shows the server validation erros but only the PartialView ascx code is rendered.
The Url looks like this after the post:
http://xxxxxxxxxxx/Home/Request
What I want is showing the entire Home view with the ascx inside showing server validation errors.
Try to do a partial submit using jQuery:
<script type="text/javascript">
$(document).ready(function () {
$("input[type=submit]").live("click", function () {
var f = $("input[type=submit]").parents("form");
var action = f.attr("action");
var serializedForm = f.serialize();
$.ajax({
type: 'POST',
url: action,
data: serializedForm,
success: function (data, textStatus, request) {
if (!data == "") {
// redisplay partial view
$("#formDiv").html(data);
}
else {
// do whatever on sucess
}
}
});
return false;
});
});
</script>
Assuming your view/ascx/HTML is something like this:
<div id="formDiv">
<% Html.RenderAction("Request"); %>
</div>
Change return type also:
[HttpPost]
public PartialViewResult Request(RequestModel model)
{
if (ModelState.IsValid)
{
// Saving data .....
}
else
{
// Show Server Validation Errors
return PartialView();
}
}
I was facing same issue in code, so I just made a small modification in my code and it worked.
Instead of returning the same view, I used
return Redirect(Request.Referrer)
Earlier:
return View();
Hey everyone. Got a custom on how to do this as im new to MVC and trying to get a couple of small things implemented. This is the way I did it in WebForms but want to transition it to MVC.
I have a user control that contains CSS which will render a message. This control is located in the MasterPage and called from a ASPX page like this:
Pseudo code:
try{
Msg.MessageMode = WebPageMessageMode.OK;
Msg.ShowOK("Report deleted.");
}
catch
{
Msg.MessageMode = WebPageMessageMode.ErrorMessage;
Msg.ShowError("There was a problem deleting the report.");
}
Masterpage.aspx
<cc1:WebPageMessage runat="server" ID="msg" />
I currently have the control in the MasterPage and now im a bit confused about proceeding from here.
Should I put the 'Msg' object above from the pseudo code to a View from the MasterPage?
What is the proper way to do something like?
I dont think there is a one-solution-fits-all here.
Anyway this is my solution that uses jQuery:
1) Create a MyResultModel class to handle a message to the user
public enum MyResultType { Info, Error }
public class MyResultModel
{
public MyResultModel( MyResultType type, string message ) {
switch ( type ) {
case MyResultType.Info: Title = "OK"; break;
case MyResultType.Error: Title = "Error!!!"; break;
}
Message = message;
}
public String Title { get; set; }
public String Message { get; set; }
}
2) Create a Partial View named MyResult in the Shared Folder to handle the model
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyResultModel>" %>
<div id="resultTitle"><%: Model.Title %></div>
<div id="resultMessage"><%: Model.Message %></div>
3) Create and use a BaseController for your controllers and add the following method to it. The method simply add a custom Http Header to the response
protected PartialViewResult PartialView( string viewName, object model, string resultHeader ) {
Response.AppendHeader( "MyHttpCustomHeader", resultHeader );
return base.PartialView( viewName, model );
}
4) In your action return a MyResultView when you've done
[HttpPost]
public virtual ActionResult DoSomething() {
try {
//Do Something
return PartialView( "MyResult",
new MyResultModel( MyResultType.Info, "Operation Completed" ),
"HttpResultInfo" );
}
catch ( Exception ex ) {
return PartialView( "MyResult",
new MyResultModel( MyResultType.Error, ex.Message ),
"HttpResultError" );
}
}
5) Finally, Submit the form using jquery and handle the results.
$.ajax({
type: "post",
dataType: "html",
url: "your/url/here",
data: $("#myform").serialize(),
success: function (response, status, xml) {
var resultType = xml.getResponseHeader("MyHttpCustomHeader");
if (resultType == null) {
//No message do whatever you need
}
else {
//response contain your HTML partial view here. Choose your
//desidered way to display it
}
}
});
With a scenario like this you dont need to place a control on the master page. You can:
Show the view as it comes from the action without any modification
Use some fancy message display technique as StackOverflow does with the orange sliding message (in this case simply extract the title and the message from the returned html)
Use some fancy jquery plugin as jGrowl to show your message
If you want to check wether it is an Info/Error message simply check the custom header with jQuery in the else branch
var title = $(response).filter("#resultTitle").text();
var message = $(response).filter("#resultMessage").text();
if (resultType == "HttpResultInfo") {
showInfoMessage(title, message);
}
else if (resultType == "HttpResultError") {
showErrorMessage(title, message);
}
Hope it helps!
In a controller, as part of the action, you can set a message like this:
public ActionResult MyAction()
{
// Do some stuff
TempData["message"] = "This is a message.";
return View("MyView");
}
In your master page or in your view:
<%
string text = TempData["Message"] as string;
Response.Write(text);
%>
The setup:
The controller contains a method public ActionResult SaveFile() which returns a FileContentResult.
What works:
The view contains a form, which submits to this action. The result is this dialog:
What doesn't work:
The view contains some javascript to do an AJAX call to the same controller action where the form would post. Rather than triggering the aforementioned dialog, or even the AJAX success function, the response triggers the AJAX error function, and the XMLHttpRequest.responseText contains the file response.
What I need to do:
Make the request for the file using AJAX, and end up with the same result as when submitting a form. How can I make the AJAX request provide the dialog that submitting a form shows?
Here's a quick example I made up. This is the concept LukLed was talking about with calling SaveFile but don't return file contents via ajax and instead redirect to the download.
Here's the view code:
<script src="../../Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
// hide form code here
// upload to server
$('#btnUpload').click(function() {
$.ajax({
type: 'POST',
dataType: 'json',
url: '<%= Url.Action("SaveFile", "Home") %>',
success: function(fileId) {
window.location = '<%= Url.Action("DownloadFile", "Home") %>?fileId=' + fileId;
},
error: function() {
alert('An error occurred uploading data.');
}
});
});
});
</script>
<% using (Html.BeginForm()) { %>
<div>Field 1: <%= Html.TextBox("field1") %></div>
<div>Field 2: <%= Html.TextBox("field2") %></div>
<div>Field 3: <%= Html.TextBox("field3") %></div>
<button id="btnUpload" type="button">Upload</button>
<% } %>
Here's the controller code:
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public JsonResult SaveFile(string field1, string field2, string field3)
{
// save the data to the database or where ever
int savedFileId = 1;
// return the saved file id to the browser
return Json(savedFileId);
}
public FileContentResult DownloadFile(int fileId)
{
// load file content from db or file system
string fileContents = "field1,field2,field3";
// convert to byte array
// use a different encoding if needed
var encoding = new System.Text.ASCIIEncoding();
byte[] returnContent = encoding.GetBytes(fileContents);
return File(returnContent, "application/CSV", "test.csv");
}
public ActionResult About()
{
return View();
}
}