Pass data from one view to another view -MVC - c#

What would be the best method to transfer data from one view to another view? or is this bad practice?
The reason is that i want to display #model.count() from one view to the homepage, basically a summary of all the views on the homepage. There is tempdata, html.helper etc but id like to know the best and most reliable method. Thus avoiding problems further on down the line
here is the code in question
product.cshtml
<p>Total amount of Products = #Model.Count()</p>
i basically want that same value to display on the homepage

You'd have to refresh the homepage for the value to actually 'update.' At that point you may as well pass the value back in as a parameter, but I think that's not what you're hoping for.
It probably isn't the cleanest solution, but I would think you'd want your text on the main page to be settable via some javascript/jquery.
Main Page has this snippet:
<form id="PassBackVals"
<input type="hidden" name="ProductCount" value="0">
</form>
<script>$( ".ProductCount" ).change(function() {
$("$CurrentProductCount").text = $(".ProductCount").val;
});
</script>
and the Area displaying the text itself on the main would have something along the lines of
<p> I'm currently showing <div id="CurrentProductCount">0</div> Products </p>
Then in your product.cshtml, you'd have
<script>$(".ProductCount").val = #Model.Count()
$( ".ProductCount" ).change();
</script>

Ok i looked into other methods and resolved the issue by moving the code behind the viewbag into a public method below
[OutputCache(NoStore = true, Location = OutputCacheLocation.Client, Duration = 10)]
public ActionResult UpdateTotals()
{
JobController j = new JobController();
ViewBag.JobCount = j.JobCount();
ProductController p = new ProductController();
ViewBag.ProductCount = p.ProductCount();
return PartialView("UpdateTotals");
}
then i added the viewbags into a partial view and using setinterval() javascript,
<div id ="UpdateTotals">
#{ Html.RenderAction("UpdateTotals");}
</div>
<script>
setInterval("$('#UpdateTotals').load('/home/UpdateTotals')", 10000);
</script>
i was able to refresh the data constantly to my desire without the mess of pulling data through views via javascript.
hopefully this will help anyone in future :)

Related

Bizzare behavior of MVC Action/RenderAction, ajax post, and Partial Views

So the design ideal is to have one page with a couple different 'widgets' in this MVC app. Each 'widget' should be able to submit information back to itself and reload only itself. Simple in web forms, not so much with MVC it seems
First, we have our main page controller, nothing special
public ActionResult Index()
{
return View();
}
Next, we have our main page View. Note that I have tried both Action and RenderAction and there is no change in behavior
#Html.Action("Index", "Monitor", new { area = "Statistics" });
<div id="messages">
#Html.Action("Index", "Messages", new { area = "Data"});
</div>
#section Script {
<script src="#Url.Content("~/Scripts/jquery-1.9.1.min.js")" type="text/javascript"></script>
<script type="text/javascript">
$('#filter').click(function () {
$.ajax({
method: 'POST',
url: '#Url.Action("Index", "Messages", new { area = "Data"})',
success: function(data){
$('#messages').html(data);
}
});
return false;
});
</script>
The Index ActionResult in the Messages Controller:
public ActionResult Index()
{
var model = GetMessages();
return PartialView(model);
}
For the sake of brevity, going to skip the whole of Monitor Index View, and only give a brief version of Messages Index View
#using (Html.BeginForm("Index", "Messages", FormMethod.Post))
{
//Some fields to limit results are here, with style classes
<button type="submit" id="filter">Filter</button>
}
#foreach(var item in Model)
{
//Display results
}
Upon loading the main page, all looks good. The fields to limit results are displayed, as well as messages. I can enter something into the fields, click Filter, and am returned to the main page but! ...the fields have lost their style classes and the messages are unfiltered.
Strange, but more strange is if I again enter information in the fields and click Filter, this time I am not taken to the main page, but get only the Partial View of the Messages Index displayed and the messages are not filtered.
I can't say that the filtering not working is related to this issue or not, but the non-consistent behavior of clicking Filter is the part that bothers me. Anyone like to point out what I am doing wrong in here?
You probably should be using Ajax.BeginForm rather than Html.BeginForm in your widgets. That will let the widgets manage their own posts:
<div id="messages">
#using (Ajax.BeginForm("Index", "Messages", new AjaxOptions { UpdateTargetId = "messages" }))
{
// fields content
}
// other widget content
</div>
The "bizarre" behavior you're seeing is happening because on page load the submit event for your #filter button is being hijacked using jQuery, but after the first replacement of the widget content the #filter submit event is no longer being hijacked so when you click it the whole page is submitted. If you don't want to use Ajax.BeginForm you'll need to use $.on rather than $.click to sign up events, as it will handle events for matching elements which are created after the event sign up script has run.

Displaying blog categories in partial view on layout page

Currently I have a partial view where I manually display all my blog categories with links. I would like to make it dynamic by pulling from the database. I am not sure how to accomplish this within a partial view. I would even be willing to do it within the actual _layout page if it's easier that way.
Here is what I have right now.
_Categories.cshtml
<h2>Categories</h2>
<hr/>
<p>
ASP.Net MVC<br/>
Ruby on Rails<br/>
</p>
I would like to create these links dynamically as opposed to hard coding.
_Layout.cshtml
#Html.Partial("_Categories")
The main problem is there is no controller for the layout of a partial which is why I can't figure out how to go about it.
Thanks in advance for any help.
Create a controller action named ListCategories in BlogController (or in a new CategoryController). Add all the categories to the ViewBag in the action by querying them from your back-end database
public ActionResult ListCategories()
{
ViewBag.Categories = db.Categories;
}
And use a #foreach loop in the view for the action ListCategories.cshtml:
<h2>Categories</h2>
<hr/>
<p>
#foreach(Category c in ViewBag.Categories)
{
#c.Name<br/>
}
</p>
Finally, change your _Layout.cshtml to point to this action:
#Html.Action("ListCategories")
// or #Html.Action("ListCategories", "CategoryController")

How to populate textfields from a dropdown in MVC 4 with razor and c#?

I am working on a "Challenge Engine" web application that allows users to create challenges and compete with each other. I am using MVC 4 C#, razor syntax.
I am trying to make a page where the user can either create a challenge, or edit the details of a challenge he has already created. The way I want this to work is to have a drop-down menu of the challenges a user owns, a submit button, and two text fields below. When a challenge is selected from the drop-down, the two text fields should populate with the challenge name and the challenge description. I am not sure how to accomplish this, although I think it may involve somehow calling additional code that needs to be put into the controller (although maybe not). It may also require JavaScript, jQuery, and/or AJAX, but my understanding of these technologies is still somewhat shaky. Can anyone help, or point me in the right direction? I have Googled this extensively the past couple of days and searched stack overflow, but couldn't find anyone doing quite what I'm trying to do.
Below is the relevant code I have so far.
The Challenge Model:
public class ChallengeModel
{
public int ChallengeId { get; set; }
public String Name { get; set; }
public String Description { get; set; }
}
The Challenge Controller:
public class ChallengeController
public ActionResult Index()
//Note: UserService and Challenge Service are part of the service layer;
//They simply encapsulate the methods in the various DAOs.
{
ViewBag.CurrentUserName = WebSecurity.CurrentUserName;
ViewBag.CurrentUser = UserService.GetUserByName(ViewBag.CurrentUserName);
ViewBag.OwnedChallenges =
ChallengeService.GetActiveChallengesByParticipant(CurrentUser);
return View();
}
The Challenge View (index.cshtml):
<div class="challengeOwner">
<em>Challenges you own:</em>
<select id="selectOwnedChallenges">
<option>Create new challenge...</option>
#foreach (ChallengeModel Challenge in ViewBag.OwnedChallenges)
{
<option id="#Challenge.ChallengeId"
value="#Challenge.ChallengeId"
onclick=" [[[INSERT CODE HERE THAT WILL POPULATE TEXT FIELDS
WITH CHALLENGE NAME AND DESCRIPTION]]] ">#Challenge.Name</option>
}
</select>
<input id="ChallengeName" type="text" name="Name"
value="#selectedChallenge.Name"/><br />
<input id="ChallengeDescription" type="text" name="Description"
value="#selectedChallenge.Description"/>
<input id="updateChallenge" type="button" value="Submit" />
</div>
As you can see, I thought I would use a variable #selectedChallenge to represent the challenge selected in the drop-down. I don't know how to set it, and I'm thinking this is probably not how it should be done, but I left it there for now so you can see my intention. Any help would be greatly appreciated.
Thanks in advance!
You can use data attributes to hold the name and description of each option.
<option value="#Challenge.ChallengeId"
data-name="#Challenge.Name"
data-description="#Challenge.Description">
#Challenge.Name</option>
Then use jQuery to update the input fields when the select changes:
// this runs when the DOM is finished loading http://api.jquery.com/ready/
$(document).ready(function() {
// wire up the change handler http://api.jquery.com/change/
$("#selectOwnedChallenges").change(function() {
// get the selected option's data values http://api.jquery.com/data/
var data = $("#selectOwnedChallenges option:selected").data();
// set the inputs
$("#ChallengeName").val(data.name);
$("#ChallengeDescription").val(data.description);
});
});
You need to use javascript for this. Its fairly easy. Here is a quick function i wrote that would do what you need.
<script type="text/javascript">
function displaySelectedChallenge(name, description)
{
$("#ChallengeName").val(name);
$("ChallengeDescription").val(description);
}
</script>
Then call this function after the selection is made:
displaySelectedChallenge(#Challenge.Name, #Challenge.Description)

Paging data in MVC3 AJAX

For the site I'm currently working on, I have a list of products which I need to display in a paged list. The list needs to be used on several different pages, each of which has their own rules for how to retrieve their list of products. The list pages need to refresh with AJAX. I'm using LINQ-2-SQL to talk to the database, and MVC3/Razor as the view engine.
So far so good.
What I need help with is figuring out how to implement this. I'll explain what I've done so far, and what isn't working, and I hope someone can give me some direction of the best way to get this working, whether it be bug fixes, missing options, or a redesign. Note that the setup described above is immutable, but everything else can be altered.
For the first set of data, I have Index.cshtml. This will be a list of all products. There will be other sets (such as a list of all products in a category, but I can do the selection for that just fine), but this is the primary test case.
Currently, I have an object to represent the state of the grid: PagingData. The details of it aren't really important, but it takes an IEnumerable when first instantiated, it stores itself in HttpContext.Current.Session between requests, and it has a function that returns an IEnumerable of the products that are supposed to be on the current page. I tried it as an IQueryable<>, but that didn't work.
Currently, I am getting an IQueryable.ToList() and setting it as the data for a DataPager that's used as the Model of a Partial view called _ProductList.cshtml. _ProductList primarily consists of a pager control (another partial) and a foreach loop across the Model to display a partial for each Product.
_ProductList.cshtml:
#model PagingData
<script type="text/javascript">
$(function() {
$('#productList a.pagerControl').live('click', function() {
$('#productList').load(this.href);
return false;
});
</script>
<div id="productList">
#Html.Partial("_Pager", Model)
#foreach (var item in Model.ProductsOnPage)
{
#Html.Partial("_ProductListGridDetail", item);
}
</div>
_Pager uses: #Html.ActionLink(page.ToString(), "_ProductListSetPage", new { newPage = page }, new { #class = "pagerControl" }) to provide the links to change pages (the page variable is the number of the page to draw, from a loop).
This solution works, kindof. The problem I'm having with it is that the only way to update the PagingData with the new page is via a Controller, and each method of modifying the pager (page, # of products per page, format, sort) will need its own controller because I can't overload them. This also means _Pager produces URLs like http://localhost:52119/Product/_ProductListSetPage?newPage=3 instead of http://localhost:52119/Product.
I've tried Ajax.ActionLink(), and wrapping the whole thing in an Ajax.BeginForm(), but neither seemed to work at all. I do have the jquery.unobtrusive-ajax.js library included.
Is this approach feasible? Should I replace the PagingData object with something else entirely? I do not want the paging data in the URL if it's at all possible to avoid it.
If you don't want the page in the url you could use a <form> instead of link, like this:
#using (Html.BeginForm("Index", "Product")
{
#Html.Hidden("newPage", page)
<input type="submit" value="#page" />
}
Which should generate a form for each page with a hidden field containing the actual page number, for example:
<form action="/Product" method="post">
<input type="newPage" value="3" />
<input type="submit" value="3" />
</form>
Now all that's left is to AJAXify this form:
$(function() {
$('#productList form').live('submit', function() {
$.post(this.action, $(this).serialize(), function(result) {
$('#productList').html(result);
});
return false;
});
});
Which would invoke the Index action on ProductController:
public ActionResult Index(int? newPage)
{
var model = ... fetch the products corresponding to the given page number
return PartialView(model);
}

How to access .net MVC ViewData from Jquery directly

I am passing viewdata into my aspx page like so:
//Controller
List<user> userList = Data.GetAllUsersForCompany(companyId);
List<SelectListItem> dropDownList = FormatUserList(userList);
ViewData["UserList"] = userList;
ViewData["FormattedUserList"] = dropDownList;
return View();
I am populating a drop down with the name of a user, which I want to bind with Jquery so that when the user changes the drop down this in turn updates the input fields with the current selected user.
The ASPX page:
<p>
<%= Html.DropDownList("userSelected", (List<SelectListItem>)ViewData["FormattedUserList"] )%><br /><br />
<%= Html.TextBox("userFName")%><br />
<%= Html.TextBox("userLName")%><br />
<%= Html.TextBox("userEmail")%>
</p>
I hook up Jquery to detect the drop-down changes which work, but how do I manipulate the input boxes with data?
<script type="text/javascript">
$(document).ready(function() {
$("#userSelected").change(function() {
var pkUser = $("#userSelected").val();
alert("Current UserID is " + pkUser); //works up to here just fine
$("#userFName).val() = ViewData["UserList"].Select(x => x.pkUser == valueOfDropDown).fName; ???
.
.
.
});
});
</script>
Am I doing things completely wrong? Can you point out what the best practice is for this scenario. If I can get away from having postbacks that would be ideal.
Soul (MVC newbie)
It looks like you are mixing your javascript and c#, remember that the javascript only executes client side, and the c# only executes server side. That being said, if you want to have some of your viewdata hanging around for your javascript to use on the client side, you need to encode it in the page somewhere the javascript can get at it. The easiest way I can think of is to use a JavaScriptSerializer and embed the values into your javascript, kind of like:
<%
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
%>
<script type="text/javascript">
var users = <%= serializer.Serialize(ViewData["UserList"]) %>;
//Use the users variable now with a copy of the view data.
</script>
In most cases, it is better to have static javascript files. It's not universally the case, but its often very hard to manage code that's parsed together at runtime. So rather than trying to write serverside code in your script tags (like the line that seems to be breaking), you should try writing the data to a hidden part of the page, perhaps, and then getting that data with jQuery.
You should be able to output a hidden form element with the value of any data that you want to use later on.
Say your output was:
<input type="hidden" id="fname_store" name="fname" value="soul" />
This could also be a single variable that is set in an inline script if you find this method messy:
<script type="text/javascript">
var data = <% serialized_data_from_the_server_side %>;
</script>
Then your line that breaks would be something like this:
$('#userFName').val($('#fname_store').val());
Notice that you are missing a quote in your code at the end of the selector, and also notice that the jQuery val() function is set by passing it a value, not setting it equal to a value.
Best of Luck!
You can always update your Action.
List<user> userList = Data.GetAllUsersForCompany(companyId);
List<SelectListItem> dropDownList = FormatUserList(userList);
return Json(new { UserList = userList, FomattedUserList = dropDownList} );

Categories

Resources