Problems with RenderAction in MVC 3 - asp.net-mvc-3

I wanted use MVC and renderpartial to generate a menu but but could not get it to work, and from what I read it seemed maybe RenderAction would be more suitable. Still I have not gotten it to work.
What I intended to do was create a controller that selects certain articles from a database that will act as categories (this is put into HomeController):
public ActionResult MenuController()
{
var movies = from m in db.Art
where m.ArtikelNr.StartsWith("Webcat")
select m;
return View(movies);
}
And then send that information to a view:
#model IEnumerable<xxxx.Models.Art>
#{
Layout = null;
}
<ul>
#foreach (var item in Model)
{
<li>#Html.DisplayFor(modelItem => item.Benämning_10)</li>
}
This works when I just run it as a normal controller and view, it returns a list of what I want. But if I want to call it from _layout.cshtml (because this menu should appear on every page) like this:
<div id="sidebar">#Html.RenderAction(MenuController)</div>
Then it generates the following error:
CS0103: The name 'MenuController' does not exist in the current context
What is the proper way of calling an action/view/whatever from the _layout.cshtml file?

You should call
#Html.RenderAction("_MenuController")
and be sure that you have a working rule in your Global.asax
As suggested in another answer would be better to use
return PartialView();
I also suggest you to use the ChildActionOnlyAttribute to be sure that this action will never be called as a standard action.
So something like that:
[ChildActionOnly]
public PartialViewResult _MenuController()
{
var movies = from m in db.Art
where m.ArtikelNr.StartsWith("Webcat")
select m;
return PartialView(movies);
}

#{Html.RenderAction("MenuController");}
or
#Html.Action("MenuController")

Simply
#Html.RenderAction("MenuController")
You've forgotten quotes around your string parameter

<div id="sidebar">#Html.RenderAction("_MenuController")</div>
Quotes around your action name :) It might also be good practice to return a partial view:
return PartialView(movies);

Related

How to display a fully formed HTML page as an MVC view?

MVC/ASP.NET/C#/html/javascript newbie question:
I'm trying to move some legacy software into an MVC solution. I have an MVC controller ViewResult method that makes an API call to the legacy system and returns a string which is a fully formed HTML page (including the HTML start and end tags). Some time in the future, I'll rewrite the logic as an MVC view, but for right now I need to just display that page (preferably in a new tab).
I've tried this in the controller:
return View((object)calendar);
(where "calendar" is the string containing the HTML document)
In my view I have
#model string
#{ Layout = null; }
#Model
But that didn't work.
Any ideas?
Model binding is binding the object of your model class.
For example, ([Solution].[Models].[Model class]),
#model PassDatainMVC.Models.Record
To pass the data from controller to view,
Approach 1: ViewBag
Controller:
string data = "testing";
ViewBag.see = data;
return View();
View:
#using PassDatainMVC.Models
#ViewBag.see
Or:
Approach 2: Model binding
Controller (Class):
public string recordProperty;
View:
#model PassDatainMVC.Models.Record
#Model.recordProperty
While you have to set the property under the model class in the data field for the second approach.
Ref. https://www.c-sharpcorner.com/article/asp-net-mvc-passing-data-from-controller-to-view/
If you want to just one data you can use a ViewBag. This is simple.
Also you want to send with model. You should use this code.
Class
public class Calendar
{
public string CalendarName { get; set; }
}
Controller
Calendar newModel = new Calendar();
newModel.CalendarName = "test name...";
return View(newModel);
View
#model ModelNamespace.Calendar
<h1> #Model.CalendarName </h1>
Thanks Reha! But unfortunately neither of your suggestions did the trick.
For your first suggestion I used ViewBag. In the controller I replaced
return View((object)calendar);
to
ViewBag.calendar = calendar;
return View();
And replaced the view with just
#{ Layout = null; }
#ViewBag.calendar
The result was that the user is left looking at the actual HTML code instead of what the HTML code is supposed to render.
For your 2nd suggestion, I did exactly as you suggested (except I changed
Model.CalendarName = "test name...";
to
Model.CalendarName = calendar;
The result is the same, the user is left looking at the HTML code.

Retrieve form data in action method : ASP.NET MVC 3

I am trying to use a simple form with only a text field to get some information that will be used in an action method to redirect to a different action method. Here's the context:
I have a route mapped in my global.asax.cs file which prints "moo" the given amount of times. For example, if you typed "www.cows.com/Moo8", "Moo" would be printed 8 times. The number is arbitrary and will print however many "Moo"s as the number in the URL. I also have a form on the homepage set up as follows:
#using (Html.BeginForm("Moo", "Web"))
{
<text>How many times do you want to moo?</text>
<input type="text" name="mooNumber" />
<input type="submit" value="Moo!" />
}
The number submitted in the form should be sent to the action method "Moo" in the "Web" controller (WebController.cs):
[HttpPost]
public ActionResult Moo(int mooNumber)
{
Console.WriteLine(mooNumber);
return RedirectToAction("ExtendedMoo", new { mooMultiplier = mooNumber });
}
Finally, the "Moo" action method should send me back to the original "www.cows.com/Moo8" page; as you can see above I simply used an already existing action method "ExtendedMoo":
public ViewResult ExtendedMoo(int mooMultiplier)
{
ViewBag.MooMultiplier = RouteData.Values["mooMultiplier"];
return View();
}
How can I access the value submitted in my form and use it in the last call to "ExtendedMoo"?
Refer to this post or this, you might get some idea how routing works. Something is wrong with "www.cows.com/Moo8", try to find it out. Hint "{controller}/{action}/{parameter_or_id}"
Instead of RedirectToAction, use Redirect and create the Url.
This should do the trick:
return Redirect(Url.RouteUrl(new { controller = "Web", action = "ExtendedMoo", mooMultiplier = mooNumber }));
I hope i helps.
Oh wow. Turns out that form was on my Homepage, so instead of using "Moo" as the action method, I needed to override the "Homepage" action method with a [HttpPost] annotation over THAT one. Didn't realize that forms submitted to the page they were rendered from - that was a really useful piece of information in solving this problem!
Thanks all for your attempts at helping out!
If I understood right
You can you use form Collection to get the value from textbox.
Make Sure the input tag has both id and name properties mentioned otherwise it wont be available in form collection.
[HttpPost]
public ActionResult Moo(int mooNumber, **formcollection fc**)
{
**string textBoxVal= fc.getvalue("mooNumber").AttemptedValue;**
Console.WriteLine(mooNumber);
return RedirectToAction("ExtendedMoo", new { mooMultiplier = mooNumber });
}

Pre-populate Create View

After selecting an accountholder I want to prepopulate my Order Create View with the properties of the selected accountholder.
My Controller Action so far:
[HttpPost]
public ActionResult Create(FormCollection values)
{
var accountHolder = from a in unitOfWork.AccountHolderRepository.Get(includeProperties: "AccountHolder")
where a.CustSName == values["Name"]
select a;
foreach (var a in accountHolder)
{
ViewBag.CustFName = a.CustFName;
ViewBag.CustSName = values["Name"];
ViewBag.CustPhone = a.CustPhone;
ViewBag.CustEmail = a.CustEmail;
}
return RedirectToAction("Create", "Order");
}
Not sure if I understand correctly what are you trying to accomplish here. I'm assuming :
Displaying Empty Create form
User provides value for AccountHolder (automatic submit happens?)
You return pre-populated form
Final Create step to preserve values to database
Am I right ?
If so, instantiate the model / viewmodel you're using in your create form (you're using strongly typed view right ?) and return it like this :
return View(yourobject); //Assuming the first view returned by GET request to Create action has all the properties in place
however that should happen only if the values are missing, right. so you might want to add some more logic to your controller to verify if pre-popullation or db.Save() is required.
As you're calling RedirectToAction to the Order controller, I assume you are now in the Create method of the accountholderController?
What's your question exactly? Without specifics, I can't give you much help.
Some notes though:
Try to search for the accountholder based on its ID in the database rather than the name. You are now trusting your enduser to enter the accountholder name exactly as it is entered in the database (same case, same punctuation). ID's are more precise and require less effort to get right.
Why use the Post-Create method if all you want to do is select an accountholder from a list and then open a Create view? It would be much wiser to have a dropdownlist containing all accountholders on your main page (or wherever you want to put it). something along the lines of
<select name="accountholderID">
<option value:"ID_of_accountholder">Name_of_accountholder</option>
...
</select>
Add a button next to that. Once an accountholder is selected and the button is clicked, call your (Get, not Post) Create method in the OrderController. Pass the accountholderID as a parameter. Your Create methoud should be something like:
public ActionResult Create(string accountholderID)
{
int ID = Convert.ToInt32(accountholderID);
ViewData["Accountholder"] = database.tbl_Accountholders.SingleorDefault(x=> x.Id == ID);
...
And in your Create View just access the values of your accountholder like so:
<% var accountholder = (accountholdertype)ViewData["Accountholder"]; %>
<span> Name is <%: accountholder.Name %> </span>
I think that should get you where you want to be :-)

My controller viewmodel isn't been populated with my dynamic views model

Im creating an application that allows me to record recipes. Im trying to create a view that allows me to add the basics of a recipe e.g. recipe name,date of recipe, temp cooked at & ingredients used.
I am creating a view that contains some jquery to load a partial view clientside.
On post im having a few troubles trying to get the values from the partial view that has been loaded using jquery.
A cut down version of my main view looks like (I initially want 1 partial view loaded)
<div id="ingredients">
#{ Html.RenderPartial("_AddIngredient", new IngredientViewModel()); }
</div>
<script type="text/javascript">
$(document).ready(function () {
var dest = $("#ingredients");
$("#add-ingredient").click(function () {
loadPartial();
});
function loadPartial() {
$.get("/Recipe/AddIngredient", {}, function (data) { $('#ingredients').append(data); }, "html");
};
});
</script>
My partial view looks like
<div class="ingredient-name">
#Html.LabelFor(x => Model.IngredientModel.IngredientName)
#Html.TextBoxFor(x => Model.IngredientModel.IngredientName)
</div>
<div class="ingredient-measurementamount">
#Html.LabelFor(x => Model.MeasurementAmount)
#Html.TextBoxFor(x => Model.MeasurementAmount)
</div>
<div class="ingredient-measurementtype">
#Html.LabelFor(x => Model.MeasurementType)
#Html.TextBoxFor(x => Model.MeasurementType)
</div>
Controller Post
[HttpPost]
public ActionResult Create(RecipeViewModel vm,IEnumerable<string>IngredientName, IEnumerable<string> MeasurementAmount, IEnumerable<string> MeasurementType)
{
Finally my viewmodel looks like
public class IngredientViewModel
{
public RecipeModel RecipeModel { get; set; }
public IEnumerable<IngredientModel> Ingredients { get; set; }
}
My controller is pretty ugly......im using Inumerble to get the values for MeasurementAmount & MeasurementType (IngredientName always returns null), Ideally I thought on the httppost Ingredients would be populated with all of the on I would be able Ingredients populated
What do I need to do to get the values from my partial view into my controller?
Why don't you take a look at the MVC Controlstoolkit
I think they would do what you want.
Without getting in too much detail. Can you change the public ActionResult Create to use FormCollection instead of a view model? This will allow you to see what data is coming through if any. It would help if you could post it then.
Your view model gets populated by using Binding - if you haven't read about it, it might be a good idea to do that. Finally I would consider wrapping your lists or enums into a single view model.
Possible Problem
The problem could lay with the fact that the new Partial you just rendered isn't correctly binded with your ViewModel that you post later on.
If you inspect the elements with firebug then the elements in the Partial should be named/Id'ed something like this: Ingredients[x].Property1,Ingredients[x].Property2 etc.
In your situation when you add a partial they are probably just called Property1,Property2.
Possible Solution
Give your properties in your partial the correct name that corresponds with your List of Ingredients. Something like this:
#Html.TextBox("Ingredients[x].Property1","")
Of, after rendering your partial just change all the names en ID's with jquery to the correct value.
It happens because fields' names from partial view do not fit in default ModelBinder convention. You should analyze what names fields have in your partial view.
Also you should implement correct way of binding collections to MVC controller. You could find example in Phil's Haack post
Assuming RecipeViewModel is the model being supplied to the partial view, try just accepting that back in your POST controller like this:
[HttpPost]
public ActionResult Create(RecipeViewModel vm)
{
//
}
You should get the model populated with all the values supplied in the form.

MVC3 Ajax.BeginForm odd behavior

I have a very simple view that has a DropDownListFor and a Button inside an Ajax.BeginForm helper. Clicking the button renders the whole view again inside the div I have set to update including the layout page (I also notice a spike in the cpu when clicking the button multiple times)
Here is the Ajax.BeginForm inside the view:
#using (Ajax.BeginForm("About2", "Home", new AjaxOptions { UpdateTargetId = "property22" }))
{
<div>
<div id="property22">
#Html.DropDownListFor(m => m.SomePropertyToBind, new SelectList(Model.list, "property1", "property2"))
</div>
<button type="submit" id="test">
Click me</button>
</div>
}
Any ideas where I'm going wrong?
I uploaded the whole project if someone has a couple of minutes to take a look at it:
http://www.sendspace.com/file/siu3r31 (free provider so there may be a popup)
Thanks
You are using a wrong overload of the Ajax.BeginForm helper. It should be like this:
#using (Ajax.BeginForm(
"About2",
"Home",
null,
new AjaxOptions { UpdateTargetId = "property22" },
new { #id = "refreshe" }
))
Notice the additional null value I am passing as the routeValues parameter. Also in the example you uploaded you forgot to include the TestView.cshtml view. This being said in order to fix the problem you have two possibilities:
Either return a partial view:
public ActionResult About2()
{
Random randomizer = new Random();
int random = randomizer.Next(1, 1000000000);
ModelTest newModelTest = new ModelTest();
string[] stringList = new string[] { "Red", "Blue", "Green" };
newModelTest.list = from test in stringList
select new ModelTestList
{
property1 = test,
property2 = test
};
newModelTest.SomePropertyToBind = stringList[random % 2];
return PartialView("TestView", newModelTest);
}
or disable the layout in the TestView.cshtml view:
#{
Layout = null;
}
Unfortunately from your explanation above and from the code, I am not sure what you are trying to achieve. However, I think your most worry is about having Ajax working in your view.
In your About2 action method, you are trying to return a complete view which is TestView (in that case, it doesnt exist) and passing it the newModelTest view Model. I would advise changing to return either a PartialView or JsonResult.
For example, changing the return statement of About2 action method to
public ActionResult About2()
{
...
return Json(newModelTest);
}
or changing it to a return type to string and returning "TestResult"
public String About2()
{
...
return "TestResult";
}
or you could change the return statement to return a PartialView
Thanks for your replies.
I just realized that About2 should have returned the "About" view instead of the "TestView". I had tried creating a partial view with the Ajax.BeginForm code but I came across the same problem.
This is my first attempt at Ajax.BeginForm (so far I have always used jquery), and I was under the impression that it works in a similar fashion in the sense that by specifying the target id only the contents of that element will get updated, not that the target will actually get replaced by the whole response object.
Thanks for your help, not only did I get it to work, but I now understand how it should work.
I suspect that what's happening is that you're returning the a complete View (including the layout template) in the Ajax response. Try changing your "Home" controller "About2" action temporarily to the following:
public ContentResult About2() {
return Content("Hello World");
}
I tested this sample Action with your Razor markup and clicking the button properly replaced your dropdown list with "Hello World!".
If this is indeed what's happening, then you'll want to return a View from "About2" without the layout by declaring the following at the top of the View that you're returning.
#{
Layout = null;
}

Resources