Accessing ASP.NET MVC model data from with Javascript - asp.net-mvc

I have a strongly typed View that accepts a Customer model, this customer model is a LINQ2SQL partial class that has a property called Journeys which returns all Journeys that are associated with this Customer.
I was wondering if it would be possible to access the Customer.Journeys property as a JSON object from within the Javascript.
Is this possible? If so how would I go about accessing it? Would I be best to create a FormViewModel and store the Customer details and Journey details as a JSON object there and pass it to the javascript function using something like:
<% MyJavascriptFunction(Model.JSONJourneys) %>
Or should I alter the Journeys partial class and add a .ToJson() property? Or something completely different?
Thanks.

I would do this:
Using NewtonSoft Json Library, you can convert any C# model object to Json at the client end
http://james.newtonking.com/pages/json-net.aspx
in the view
<script>
var jsobject = <%= JsonConvert.SerializeObject(Model.Journeys) %>;
function myfunction (){
//work with object
}
</script>

How about exposing your Customer model through a Javascript view and loading it as a regular javascript file in your HTML?
Like this:
In your HTML view:
<script type="text/javascript" src="/customers/123/json">
And in your controller:
public ActionResult CustomerJson(int customerId)
{
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
var customer = Customer.Get(customerId);
var serializedCustomer = serializer.Serialize(customer);
return JavaScript(
"function getCustomer() { return (" + serializedCustomer + "); }");
}

This question has long been answered (and accepted), but I wanted to pass along a response to a similar question that helped me. His answer takes advantage of MVC3/Razor syntax:
https://stackoverflow.com/a/7486214/249153:
In mvc3 with razor #Html.Raw(Json.Encode(object)) seems to do the
trick.

Related

MVC3 (Razor) Json Get deserialized data in the Controller

I need help again with Asp.Net MVC (Razor View Engine).
In my View (Index) I have
#model IEnumerable<Movie>
I want to pass the Model to the Controller: I stringify the model in this way:
<script type="text/javascript">
function postData(){
var urlact='#Url.Action("createDoc")';
var model ='#Html.Raw(Json.Encode(Model));
$.ajax({
data: JSON.stringify(model),
type:"POST",
url:urlact,
datatype:"json",
contentType:"application/json; charset=utf-8"
});
}
</script>
Everything seems to work, cause I know the stringified data is:
'[{"ID":1,"Title":"The Lord of the Rings: The Fellowship of the Ring","ReleaseDate":"\/Date(1007938800000)\/","Genre":"Fantasy","Price":93000000.00},{"ID":2,"Title":"The Lord of the Rings: The Two Towers","ReleaseDate":"\/Date(1039042800000)\/","Genre":"Fantasy","Price":94000000.00},{"ID":3,"Title":"The Lord of the Rings: The Return of the King","ReleaseDate":"\/Date(1070233200000)\/","Genre":"Fantasy","Price":94000000.00}]';
The problem is: in Controller, methodName "createDoc" (as declared in the script) I cannot access to the stringified data.
Following some samples founded on the web, my method is something like this:
[HttpPost]
public ActionResult createDoc(IEnumerable<Movie> movies)
{
//...using movies list
return View();
}
Why can't I access to the stringified data? How can I do it, is there some method to call to deserialize the model in the Controller method?
Also, can I use the serialize() method instead of the stringify() one? If so, what's the syntax, View & Controller side?
Thank you.
You've already got stringified data in your JavaScript variable model. You only need to call JSON.stringify on objects which aren't strings.
If you want to post the data to your action without modifying model, just pass in model without the JSON.stringify and the ModelBinder will take care of deserializing it to IEnumerable<Movie> for you.
If you want to use model as something other than a string, you'll want to call JSON.parse on the string. In other words:
var model = JSON.parse('#Html.Raw(Json.Encode(Model))');
Then, you'd want to keep your JSON.stringify call.
Finally, stringify is a method on a browser-specific object JSON, whereas serialize is a method on the ASP.NET MVC-specific Json object. Two different worlds, same name.

ASP.NET MVC 3 - tell partialview to regrab the viewdata values?

Let's say I have a partial view X.ascx like this:
<div id = "updateTargetIdForAjaxForm">
... javascript code which only has function definitions.
... ajax form with buttons inside
<div id = "stuff"></div>
<script type = "text/javascript">
do things to "stuff" div as soon as X.ascx is loaded.
</script>
</div>
Now I want to update things on X.ascx, based on Ajax response. Earlier, I was returning PartialView but inline javascript that does things to stuff div wouldn't like that, meaning the inline javascript just won't get executed when X.ascx is reloaded.
So is there a way I can not return PartialView in my controller, but just update ViewData values and tell the PartialView to re-grab the updated ViewData values? And also call one or two javascript functions based on the response from server maybe?
I see two possible ways to go:
Fixing your javascript code to run with dynamically loaded partial view:
http://api.jquery.com/live/
http://api.jquery.com/delegate/
These two should help you out.
The other way is to create an action on your controller that would return JSON result and from jQuery you should be able to handle JSON object and update your form. Your Action could look like :
public JsonResult GetFormValues()
{
var jsonFormValues = new
{
key1 = "abc",
key2 = "123",
key3 = "abcdef"
};
return Json(jsonFormValues, JsonRequestBehavior.AllowGet);
}
and check out http://api.jquery.com/jQuery.getJSON/ on how to handle the result

Looking for a Html.SubmitButton helper that would accept class attributes in MVC3

I would like to use a helper for Submit button in MVC3. Is such a thing available? If not, then does anyone know where I could get some code for this. I would like one that allows me to pass a class attribute.
Isn't it simple just to write
<input type="submit" class="myclassname"/>
In MVC, there are no such things like controls, that carry much application logic. In fact, it is possible but not recommended. What i want to say is that Html helpers are just making Html writing more comfortable and help you not write duplicate code. In your particular case, i think it is simpler to write direct html than that with helper. But anyways, if you want to, it is contained in MVC Futures Library. Method is called SubmitButton
Just add to your project class with such code:
using System.Text;
namespace System.Web.Mvc
{
public static class CustomHtmlHelper
{
public static MvcHtmlString SubmitButton(this HtmlHelper helper, string buttonText, object htmlAttributes = null)
{
StringBuilder html = new StringBuilder();
html.AppendFormat("<input type = 'submit' value = '{0}' ", buttonText);
//{ class = btn btn-default, id = create-button }
var attributes = helper.AttributeEncode(htmlAttributes);
if (!string.IsNullOrEmpty(attributes))
{
attributes = attributes.Trim('{', '}');
var attrValuePairs = attributes.Split(',');
foreach (var attrValuePair in attrValuePairs)
{
var equalIndex = attrValuePair.IndexOf('=');
var attrValue = attrValuePair.Split('=');
html.AppendFormat("{0}='{1}' ", attrValuePair.Substring(0, equalIndex).Trim(), attrValuePair.Substring(equalIndex + 1).Trim());
}
}
html.Append("/>");
return new MvcHtmlString(html.ToString());
}
}
}
And usage example:
#Html.SubmitButton("Save", new { #class= "btn btn-default", id="create-button" })
chk this link out it tells you how to create custom helper method, and there is no builtin submit helper ...
http://stephenwalther.com/blog/archive/2009/03/03/chapter-6-understanding-html-helpers.aspx
and it also include a very basic Submit helper method, hope it helps
There isn't a HTML helper for a button because the HTML helpers reflect over a model's propertys and help you by setting the correct attributes for binding purposes, they also look at the VilidationAttribute metadata for that property (if any) and add any jQuery validation attributes.
Buttons are not part of the model and so do not have any helpers.
You can crate your own HTML helper by following this article http://www.asp.net/mvc/overview/older-versions-1/views/creating-custom-html-helpers-cs or using the TagBuilder class: http://www.asp.net/mvc/overview/older-versions-1/views/using-the-tagbuilder-class-to-build-html-helpers-cs but I prefer to return HTMLString than a string
There isn't one but that shouldn't stop you from building one yourself.
Even though the MVC futures project doesn't appear to be moving forward at all or supported, it's not too hard to download the source, and grab the Submit button helper (and it's supporting code) to roll your own.
It's exactly how we created the base of our SubmitButton helper for a large MVC 4 project.
Here is how I did it.
Speaking of HTML 5 <button> attribute
Create a PartialView - call it like _HTML5Button.vbhtml
#ModelType YourProjectName.ButtonViewModel
<button onclick="location.href = '#Model.URL'" class="btn btn-info">#Model.ButtonText</button>
And create a ButtonViewModel
Public Class ButtonViewModel
Public URL As String
Public ButtonText As String = "Modify Button Text"
'You can add more parameters or do as you please
End Class
Then as you need to create it call you partial like this
#Html.Partial("~/Views/Shared/MiniPartialViews/_HTML5Button.vbhtml", New ButtonViewModel With {.URL = "http://www.goanywhere.com", .ButtonText = "Name That Will Appear On The Button"})
That way if you want to add more parameters later - it is all in that one partial view centralized for you - lets say you want to add an id later on
Well you go to you partial, add an id="#Model.Id" so then in your PartialView Call you just add that parameter - it does not break anything - if you ever need to add a class to that button - add it - in one place rather than searching for all the calls.
Hope that helps - it works super well for me!

ASP.NET MVC: Should Controllers called by AJAX return JSON or rendered html?

I am having trouble deciding if a controller action, which is called by AJAX, should return a partial view, or the "raw" JSON.
Returning a partial view, with rendered HTML makes it easier for the javascript to simply update the current DOM with the returned HTML. However, it does limit what javascript client consuming the webservice can do with the returned HTML.
On the other-hand, having the controller action return JSON would require the javascript making the call to "manually" create the markup based on the JSON that is returned.
So as usual, each approach has it's benefits and weakness. Are there any other pros/cons for each approach?
In my opinion, returning JSON and then letting the client side view sort it out can be messy because of the following limitations:
No standard templating language for JavaScript. In the worst case scenario, you'll be tempted to concatenate strings to form the HTML that you require.
No easy way to unit test the HTML generated by your concatenation code.
Lack of IntelliSense for your JavaScript means that you're also prone to make more mistakes.
The way I've handled this is to return rendered HTML, BUT return this rendered HTML using a partial view instead. This gives you the best of both worlds. You've got Server-side templates as well as IntelliSense support.
Here's an example:
Here's my Ajax call, as you can see all it does is replace the html for my unordered list:
FilterRequests: function() {
$.post("/Request.aspx/GetFilteredRequests", { }, function(data) {
$('ul.requests').html(data);
});
},
Here's my action on my controller:
public ActionResult GetFilteredRequests(string filterJson)
{
var requests = _requestDao.LoadAll();
return PartialView("FilteredRequests", requests);
}
Finally here is my partial view (there's no need to understand this, I'm just showing you how complex some rendering can get in a real world application. I'd dread doing this in JavaScript. You'll also notice that my partial view in turn calls other partial views as well.):
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Request>>" %>
<%# Import Namespace="Diangy.HelpDesk.Models.Lookups"%>
<%# Import Namespace="Diangy.HelpDesk.Models.Requests"%>
<%# Import Namespace="System.Web.Mvc.Html"%>
<% foreach (var request in ViewData.Model) %>
<%{%>
<li class="request">
<h2>#<%= request.Id %>: <%= request.InitialInteraction().Description %></h2>
<p>from <%= request.Customer.FullName %> (<%= request.Customer.EmailAddress %>), <%= request.InitialInteraction().UsableTimeStamp %></p>
<h3>Custom Fields & Lookups</h3>
<div class="tabs">
<ul>
<li>Custom Fields</li>
<% foreach (var lookupDefinition in (List<LookupDefinition>)ViewData["LookupDefinitions"]) %>
<%{%>
<li><%= lookupDefinition.Name %></li>
<%}%>
</ul>
<% Html.RenderPartial("CustomFields", request); %>
</div>
<% Html.RenderPartial("Discussion", request); %>
<% Html.RenderPartial("Attachment", request); %>
</li>
<%}%>
If you are using the MVC paradigm, the controller should return data (JSON) and let the view sort it out for itself, just like its job is to find/adapt the data in the model and pass it on to the view on the server side.
You get browny points for
preserving separation of concerns between logic and UI
making your ajax actions testable (good luck testing the HTML returned from that action...)
It's a bit more complicated maybe, but it fits.
You can use client-templating systems such as what is now available in the MS Ajax Toolkit to help take some of the load and preserve the logic/rendering separation on the client side.
So I'd say JSON, definitely. But hey, YMMV as usual...
I like to allow the calling app to decide. I've peiced together a MultiViewController (much of the code I found online, I'll try to update with the credit when I find it) that, based on the action extension, will return the appropriate format. for example:
myapp.com/api/Users/1 - defaults to html based on route
myapp.com/api/Users.html/1 - html
myapp.com/api/Users.json/1 - json
myapp.com/api/Users.xml/1 - xml
myapp.com/api/Users.partial/1 - returns a partial view of action name (see code)
myapp.com/api/Users.clean/1 - partial html without styling, etc...
My controllers inherit from MultiViewController and instead of "return view(Model);" I simply call "return FormatView(Model); or FormatView("ViewName",Model);". The second if I need to apply a specific view to the result - not the implied view.
The MultiViewController looks like this. Pay special attention to FormatView, whitch returns an action result:
public abstract class MultiViewController : Controller
{
private const string FORMAT_KEY = "format";
public enum FileFormat {Html, Json, Xml, Partial, Clean}
protected MultiViewController()
{
RequestedFormat = FileFormat.Html;
}
protected FileFormat RequestedFormat { get; private set; }
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
var routeValues = filterContext.RouteData.Values;
if (routeValues.ContainsKey(FORMAT_KEY))
{
var requestedFormat = routeValues[FORMAT_KEY].ToString();
if (isValidFormat(requestedFormat))
{
RequestedFormat = (FileFormat)Enum.Parse(typeof(FileFormat), requestedFormat, true);
}
}
}
private bool isValidFormat(string requestedFormat)
{
return Enum.GetNames(typeof (FileFormat)).Any(format => format.ToLower() == requestedFormat.ToLower());
}
protected ActionResult FormatView(string viewName, object viewModel)
{
switch (RequestedFormat)
{
case FileFormat.Html:
if (viewName != string.Empty)
{
return View(viewName,viewModel);
}
return View(viewModel);
case FileFormat.Json:
return Json(viewModel);
case FileFormat.Xml:
return new XmlResult(viewModel);
case FileFormat.Partial:
//return View(this.ControllerContext.RouteData.Values["action"] + "Partial");
return PartialView(this.ControllerContext.RouteData.Values["action"] + "Partial");
case FileFormat.Clean:
if (viewName != string.Empty)
{
return View(viewName, "~/Views/Shared/Clean.master", viewModel);
}
var v = View(viewModel);
v.MasterName = "~/Views/Shared/Clean.Master";
return v;
default:
throw new FormatException(string.Concat("Cannot server the content in the request format: ", RequestedFormat));
}
}
protected ActionResult FormatView(object viewModel)
{
return FormatView("", viewModel);
}
}
Clean.master is simply a master page that doesn't contain any additional html - it takes the view (so that I can consolidate any partial classes) and renders it with clean html that can be placed directly.
If I want json - the controller builds my viewmodel and then returns that view model as json, instead of sending to the default view - the same with .xml.
Partial views are a little interesting in that, by convention, all of my main views are broken down into partials, so that particular partial can be requested by itself - this comes in handy for mimicking the functionality of an updatepanel using jquery without all the junk associated with the updatepanel.
To maintain seperation of concerns you should return JSON.
When you return html you limit what you can do with the returned data. If you need a list of data and want to present it in different ways use JSON, othewise you would have to have different methods on the server to get the different renderings of the same data.
Why not both json and html?
In current project we are making routes so you can choose from front end, which format is the best suited in some case...so why don't make two controllers, first will return expected data in json and the other controller will return same data but with html...this way you can choose from let's say jQuery what and when you want and in which format you want it...and the best thing is, for different format you just need to call different adress...
in other words, make it restful, baby! :)
cheers
As for me, I choose data-driven approach. Here is a small set of features for both:
Data-driven:
JSON from server (Controller sends model directly to response)
JS template binding (May take more time at client side)
Low bandwidth
load
It's just soooo sexy!
Html-driven:
HTML from server (Controller sends model to some partial View, it renders result and returns it - may take more time at server side)
No overload in JS binding
High bandwidth load
Not sexy, no no :)
So you can maintain MVC even with HTML-driven approach though it will be a bit harder.
If you use JQuery you should use JSON or XML because it's simpler to modify, but if your ajax call only returns items for an listbox for example you could also use html.
My personal preference is JSON or XML because use JQuery very often

Function in ASP.NET MVC

A function returns only one view.
what if I want to return multiple views in a function?
For example, I have this code:
Function Index() As ActionResult
Dim _news As DataTable = News.newsSelect()
Dim _announcement As DataTable = Announcement.SelectAnnouncement()
Return View()
End Function
I want to return _news and _announcement to be used in the aspx page. How would I do this?
Are you trying to show both sets at the same time? News and Announcements?
If so then why not implement either a PartialView or two PartialViews?
Then in your main view you can render them and pass the collection to the PartialViews?
There are heaps of samples on this and the one I recommend is in NerdDinner if you haven't already seen it.
I hope this helps. If you want sample code then let me know.
One simple way is just to have those two datasets sent in a ViewData element, which you can access in a field.
example:
ViewData["Elements"] = new SelectList(aElements, "Guid", "Name");
is consumed as:
<%= Html.DropDownList("Elements","Pick an element")%>
Also, I think that if you read between the lines of this blog post here you will find an elegant way of achieving what you want ;) but its a bit more involved..(only because you mentioned Views instead of just variables..
Quote:
We need to create our own implementation of IViewFactory. This
is responsible for locating and
creating an instance of an IView
(which both ViewPage and
ViewUserControl implement).
To “inject” (all you DI fans excuse me borrowing the term without
using a DI framework) our new View
Factory into every Controller we are
going to create our own
IControllerFactory implementation.
We need to configure the framework to use our new Controller
Factory.
Finally we can create two Views – an AJAX version and a pure
HTML version.
Building on that should be all you need
Good luck!
Ric
Assuming what you are trying to do is use both of those DataTables to populate some View, then my recommendation would be to create a wrapper object and then a strongly typed view based on this object.
The wrapper object would contain properties for all of the data elements that you need in order to render your view properly. In your case, it is 2 DataTable objects. I do not really know VB, so all my examples will be in C#. Here is an example of the data wrapper class...
public class IndexViewData
{
public DataTable News { get; set; }
public DataTable Announcement { get; set; }
}
You then might update the Index action in your controller as follows:
public ActionResult Index()
{
var viewData = new IndexViewData();
viewData.News = News.newsSelect();
viewData.Announcement = Announcement.SelectAnouncement();
return View(viewData);
}
Finally, you would need to create/update your view to be strongly typed. This is done by having your page inherit from the generic System.Web.Mvc.ViewPage<T> class. Just substitute the view data wrapper created earlier for T. To do this, you would set the inherits attribute of the <%# Page %> element. In your case, if we assume your root namespace is called "Foo", you might have the following page declaration in your Index.aspx view (added extra line breaks for readability):
<%# Page Title=""
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<Foo.Models.MyModelType.IndexViewData>"
%>
Once you have a strongly typed view for your view data wrapper, you can access the wrapper object in your view using the Model property. Here is an example of something you could do in your Index.aspx view
<%-- Output some random data (bad example, for demonstration only) --%>
<%= Model.News[0]["title"] %><br/>
<%= Model.Anouncement[0]["body"] %>
In reality you're probably going to do something like iterate over each row of the data table. Regardless, once you create the strongly typed view, your model object, which was passed to the view in the Index method of the controller, is available in the Model property within the view.
You can find detailed tutorials at the ASP.NET MVC site

Resources