I have a PartialView that displays IEnumerable<Movie>.
_MoviePartial.cshtml
#foreach(var movie in Model) {
<div class="content">
<span class="image"><img src="#movie.Posters.Profile" alt="#movie.Title"/></span>
<span class="title">#movie.Title</span>
<div class="score`">
<span class="critics-score">#movie.Ratings.CriticsScore</span>
<span class="audience-score">#movie.Ratings.AudienceScore</span>
</div>
#Html.ActionLink("Add Movie", "Add", "MyMovies")
</div>
}
When the user clicks the "Add Movie" ActionLink I am going to do an ajax post to add the selected movie to the users collection. My problem is that I would like to send the entire selected Movie class to the "Add" action but not sure how to serialize each movie since the entire Movie class is not rendered in the PartialView, just a few properties. I know I can serialize something like this...
<script type="text/javascript">
var obj = #Html.Raw(Json.Encode(movie));
</script>
But I'm not sure how that would work inside a foreach loop that renders html, especially inside a PartialView.
So, just to be clear, when a user clicks the "Add Movie" ActionLink I would like to send the serialized Movie class for that respective movie to my controller via ajax.
My questions is...
Is there a better way to serialize each movie and append it to it's respective anchor? I know there's the data- html5 attribute but I thought they only allow string values, not json objects. I also know I could use jQuery's .data() function but I'm struggling to think through how to get that to run from a PartialView, especially since the html rendered by _MoviePartial.cshtml may be returned from a controller via ajax.
A framework such as knockout.js would really make your life easier here.
Basically, you would:
Load all the movie data as a JSON array using eg: Json.Encode(Model);
Create a foreach template using knockout to render your data. Knockout will then handle the trouble of keeping the displayed movies to a complete movie model.
My preference is to return a JSON object as the response with two properties; HtmlString and Data. HtmlString may contain a rendered partial view and Data may contain a serialized object of the request.
I find this is insanely easier to work with JSON, then trying to return HTML with embedded JSON object(s).
Related
Here's the situation: I have a Razor-generated list of items (that needs to stay Razor-generated):
#model MG.ViewModels.Profile.ProfileDetailsViewModel
foreach (var interest in Model.Interests)
{
<span class="subject-title">#interest.SubjectName</span>
<a data-bind='click: function(){viewDescription(#Html.Raw(Json.Encode(interest)))}'class="subject-description-button" href="#" title="View Details">details</a>
}
Users can update the details of each item by clicking a 'Details' link that encodes the Model for the viewDescription javascript function:
self.viewDescription = function (data) {
// pull data into KO observables
self.selectedInterestDescription(data.Description);
self.selectedInterestSubject(data.SubjectName);
self.selectedInterestId(data.InterestId);
self.triggerModal(true);
};
Within the modal that gets triggered, the user can send an AJAX request to an endpoint that updates the description. This much is working as I'd expect.
What I'm struggling with is - when the user is done updating, the razor Model still has the old data. So when the user clicks 'details' from the Razor-generated list after updating, the old #model data is encoded. How can I push the updated data to the #Model from javascript?
How can I push the updated data to the #Model from javascript?
You absolutely cannot modify anything on the server from javascript. All you can do is an AJAX request to the server which will return refreshed data to the client. Remember that once the view is initially rendered there's no longer any notion of #Model on the client. So talking about updating something that doesn't exist hardly makes any sense. After your AJAX request succeeds simply update the corresponding portions of your DOM that need to be updated. The controller action that you are hitting with AJAX could return all the necessary information for that.
I have the following MVC 4 code that renders images to a page:
#foreach (var photo in #Model.ImageList)
{
<a href="#Url.Action("DeletePhoto","Listing",new { imageId = photo.ImageId })">
<img src="#Url.Action("GetPhoto", new { id = photo.ImageId })" alt="" title="Click on the image to remove it" width="250" height="190"/>
</a>
}
When the user clicks on the image, the DeletePhoto method is called on the Listing controller. I'd like to also pass to this method the model, with all values, the view is bound to. Is there a way I can do this? I'm still fairly new to MVC so I'm not sure the best way to do this.
NOTE: The view is bound to a model that contains quite a bit more information than just the images. The view is a data entry form, with the ability to include pictures. So, when the image is deleted, I want to refresh the form, and keep whatever information the user has entered so I can redisplay it. And, it's quite possible this information hasn't been saved to the DB yet.
I can recommend to read my similar question:
Is it possible to pass object as route value in mvc 3?
In few words-no,you can't do it in that way.
In my mvc application, I have a view in which the content for the view will have to be rendered in html format. html string will be obtained form the model in the view. How can i rener the html mark up as such in view?
Thanks in advance
Have a read through: http://www.asp.net/mvc/tutorials/asp-net-mvc-views-overview-cs to see an example of the ASPX view engine rendering HTML.
You shouldn't be building HTML in the model (or in the controller and putting it into the model).
Update: as Jamie Dixon has mentioned, there are situations in which business properties of the model will contain HTML.
Generally, speaking:
The model should contain properties and business logic.
The views will render the HTML that you need.
The controller calls the business logic needed and passes the model to the correct view.
If, in the view, you wish to write out a heading based on a property called Title on the Model, you can use this:
<h1><%: Model.Title %></h1>
or if you are storing a HTML string in a property called StoredHtml:
<div>
<%= Model.StoredHtml%>
</div>
Note that <%= has been used rather than <%:, as <%: will encode HTML for security reasons (like <script> tags being saved).
I have an ascx control for fruits that contains following code:
<div id = "fruits">
....
Ajax stuff1 UpdateTargetId = "fruits"
Ajax stuff2 UpdateTargetId = "fruits"
<%Html.RenderPartial("PagerAjax", (Pager)ViewData["pager"]); %>
</div>
now this fruit control can appear on a number of webpages and the pager would need to know what page the user is on so that it can pull next set of fruits accordingly. For example, if I am on red-fruit page, then PagerAjax should know I am only pulling out red fruits. So, basically I would need to know ControllerName (assume it's home) and actionName (assume it's redFruits()). (Example may seem inefficient but it makes sense for the real purpose.) Now, I could do something like this:
<%Html.RenderAction("PagerAjax", (Pager)ViewData["pager"], ViewContext.RouteData.Values["action"], controllerFilter = ViewContext.RouteData.Values["controller"] }); %>
However, as you noticed, the above RenderAction is inside the div that is being updated by Ajax callback, which means it will contain action and controller of the Ajax stuff rather than the original URL's.
What should be an efficient workaround?
You could pass the original ViewContext.RouteData.Values["action"] as parameter when calling your AJAX action. This way the action knows what was the original action and store it in the model (or ViewData as in your case I see that your views are not strongly typed). Now your markup could become:
<% Html.RenderPartial(
"PagerAjax",
(Pager)ViewData["pager"],
new ViewDataDictionary() { { "originalAction", ViewData["originalAction"] } }
); %>
Ok, I'm an MVC newbie coming from a webforms background, so please excuse any ignorance here. Here is my scenario. I've got a table consisting of a list of applications and associated permissions. Each table row consists of 3 pieces of information: a checkbox, some text describing the row, and a dropdown list allowing the user to select the appropriate permission for the application. I want to post this data and only work with the rows in the table which were checked (the id of the row is embedded as the checkbox name). From there, I want to grab the selected value from the DropDownList, and call the necessary code to update the DB. Here is my View page's code:
<%foreach (var app in newApps)
{ %>
<tr>
<td><input type="checkbox" name="AddApps" value="<%=app.ApplicationId %>" /></td>
<td><%=Html.Encode(app.ApplicationName)%></td>
<td><%=Html.DropDownList("AppRole", new SelectList(app.Roles, "RoleId", "RoleDescription"))%></td>
</tr>
<%} %>
How would I retrieve the appropriate values from the FormCollection when I get to the controller on form post? I have done this in the past when I only had checkbox values to retrieve by just calling Request.Form["CheckBoxName"] and parsing the string.
Or am I going about this entirely wrong?
You are halfway right in order to post your data that the controller can read the info it must be inside a form as so :
<% using(Html.BeginForm("Retrieve", "Home")) %>//Retrieve is the name of the action while Home is the name of the controller
<% { %>
<%foreach (var app in newApps) { %>
<tr>
<td><%=Html.CheckBox(""+app.ApplicationId )%></td>
<td><%=Html.Encode(app.ApplicationName)%></td>
<td><%=Html.DropDownList("AppRole", new SelectList(app.Roles, "RoleId", "RoleDescription"))%></td>
</tr>
<%} %>
<input type"submit"/>
<% } %>
and on your controller :
public ActionResult Retrieve()
{
//since all variables are dynamically bound you must load your DB into strings in a for loop as so:
List<app>=newApps;
for(int i=0; i<app.Count;i++)
{
var checkobx=Request.Form[""+app[i].ApplicationId];
// the reason you check for false because the Html checkbox helper does some kind of freaky thing for value true: it makes the string read "true, false"
if(checkbox!="false")
{
//etc...almost same for other parameters you want that are in thr form
}
}
//of course return your view
return View("Index");//this vaires by the name of your view ex: if Index.aspx
}
This site gives more details on how to handle the dropdownlist helper:
http://quickstarts.asp.net/previews/mvc/mvc_HowToRenderFormUsingHtmlHelpers.htm
Request.Form will still work, except that your checkboxes all have the same name.
So one way would be to give the checkboxes distinct names, e.g. "AddApps-app.id", and use Request.Form.
However, a more elegant and testable way is to use list binding.
In this model, you give your form elements a certain structured name, and the default model binder will wrap each set of form elements into a list of typed records in the controller. This is fully explained in this blog post.
The advantage here is that your controller deals only with instances of the application type, and hence has no implicit dependency on the way the view is structured. Therefore, it is very easy to unit test.