Razor behaving strangely? - asp.net-mvc-3

Razor is playing tricks with me. I have a partial view:
#model ManageMvc.Models.Default.Classes.MvcModule
#{
if (Model.CanExpand)
{
Response.Write("Crazy");
#:TEST
<text>ojiiojjiojiojiojiojiojiojio</text>
Response.Write("Crazy2");
}
else
{
Response.Write("Crazy");
#:TEST
<text>ssssssssdffffffff</text>
Response.Write("Crazy2");
}
}
This is called from this:
#if (Model.Modules.Count > 0)
{
for (var i = 0; i < Model.Modules.Count; i++)
{
Html.Partial("~/Views/UserControls/_MenuItem.cshtml", Model.Modules[i]);
}
....
}
I expected razor to print out whats written inside the Text block and the #: block. But i get nothing. When i run this it just prints CrazyCrazy2 (for each module in the list).
Did i miss something?
Updated
The code that is calling if (Model.Modules.Count > 0) is a partial itself. That one is called from the layout page. So the top code is the second partial being called. Can this make any difference?
Layout -> MainMenu (partial) -> CreateMenuItem (partial)
Updated
This is the new code: (_MenuItem.cshtml inside Shared->DisplayTemplates)
#model ManageMvc.Models.Default.Classes.MvcModule
#{
if (Model.CanExpand)
{
#:TEST
<text>ojiiojjiojiojiojiojiojiojio</text>
}
else
{
#:TEST
<text>ssssssssdffffffff</text>
}
}
Partial view MainMenu that is calling the menu item:
#Html.DisplayFor(x => x.Modules, "_MenuItem")
Now this breaks on that line and i get the following error:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[ManageMvc.Models.Default.Classes.MvcModule]', but this dictionary requires a model item of type 'ManageMvc.Models.Default.Classes.MvcModule'.

Put an # when calling the Html.Partial helper and avoid using Response.Write in an ASP.NET MVC view:
for (var i = 0; i < Model.Modules.Count; i++)
{
#Html.Partial("~/Views/UserControls/_MenuItem.cshtml", Model.Modules[i]);
}
Also instead of writing some ugly loops I would strongly suggest you using templated helpers. So replace the for loop in your layout with this simple helper:
#Html.DisplayFor(x => x.Modules)
and then define the display template (~/Views/Shared/DisplayTemplates/MvcModule.cshtml) which will be rendered for each element of the Modules collection:
#model ManageMvc.Models.Default.Classes.MvcModule
#if (Model.CanExpand)
{
#:TEST
<text>ojiiojjiojiojiojiojiojiojio</text>
}
else
{
#:TEST
<text>ssssssssdffffffff</text>
}
See how easier this is?

Related

I want to check at least one value in ng-repeat, if found, then to display <div> class

In my ng-repeat, scored/not scored are there. I want to display <div> class if at least one item in the ng-repeat has "Not Scored"
You should be determining whether or not you are displaying that div inside your controller. Doing it within the ng-repeat would mean you would have logic in your view and that's just not good practice. Here is a simple example on how to accomplish what you're wanting.
In your controller:
$scope.showDiv = false;
$scope.getItems = function () {
// fetch items via ajax...
for (var i = 0; i < data.items.length; i++) {
if (data.items[i].foo == 'Not Scored') {
showDiv = true;
}
}
}
And on your view:
<div ng-show="showDiv">
// do your ng-repeat here
</div>

Why would this partial view return a blank?

I have a partial view that I am creating to apply a special format to some decimal numbers. Here is the partial view ("_Dollar"):
#model decimal?
#if (Model.HasValue)
{ Html.Display(Model.Value.ToString("$#,0.00;$#,0.00-;0.00")); }
else { Html.Display("0.00"); }
Here is the calling line of code:
<td style="text-align:right;">#Html.DisplayFor(modelItem => item.TotalBill, "_Dollar")</td>
Any ideas of what might be going on?
Update: I should add, when running debug, the partial view is called and runs as I would expect it to. To me, is seems the problem is with how I am using Html.Display.
Update: I understand based on #Gaby's answer why my previous trial doesn't work. I made the changes, but it still doesn't work. On my view I have #Html.Partial("_Dollar",item.TotalBill) in the partial view I now have:
#model decimal?
#if (Model.HasValue)
{ Html.Raw(Model.Value.ToString("$#,0.00;$#,0.00-;0.00")); }
else { Html.Raw("0.00"); }
Html.Display does not do what you think it does.. read http://msdn.microsoft.com/en-us/library/ee310180%28v=VS.98%29.aspx
You should use
#model decimal?
#if (Model.HasValue)
{ #Html.Raw(Model.Value.ToString("$#,0.00;$#,0.00-;0.00")); }
else { #Html.Raw("0.00"); }

MVC3 Helper DisplayFor Model

I've got a view that displays a list of items. Rather than display items in a grid, I'd like to display 4 items per page, each with an image and multiple properties, displayed in a unique layout.
So, I'd like a foreach to iterate through the items, and each item to get displayed in a div. I could put all the code in the loop, but I'd like to have a custom html helper extension to do this.
I came up with this,
public static MvcHtmlString DisplayViewerFor(this HtmlHelper helper, TestModel model, bool rightAligned = true) {
if (model == null) {
model = new TestModel();
}
var outterDiv = new TagBuilder("div");
outterDiv.AddCssClass(rightAligned ? "item-display-right" : "item-display");
var image = new TagBuilder("image");
image.Attributes.Add("src", "Item/GetImage/" + model.ItemName);
image.Attributes.Add("height", "150");
var editorLabel = new TagBuilder("div");
editorLabel.AddCssClass("editor-label");
//LOOKING TO ADD CODE LIKE THIS HERE
var labelContent= html.LabelFor({my model property here})
editorLabel.InnerHtml += labelContent;
//END OF ADD
return new MvcHtmlString(outterDiv.ToString(TagRenderMode.EndTag));
}
In my method above, I need to display a few more values, and I would like to use the Html.LabelFor and Html.DisplayFor helpers, but the methods aren't available and I'm not sure what to pass to them if they were.
I'm not sure if this is possible or not, but I thought I would ask.
EDIT
I'm trying to use the html.LabelFor. See my code where I have updated it above, adding to it these two lines.
var labelContent= html.LabelFor({my model property here})
editorLabel.InnerHtml += labelContent;
You can see the code above.
EDIT 2
Here is the planned use for this Helper with dummied down view.
#model TestItemDisplayList
#{
ViewBag.Title = "Items";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#foreach(var item in #model.Items){
#Html.DisplayViewerFor(item)
}
You can use the Html.DisplayFor method to render a DisplayTemplate. One of the over loads for the method is to specify a template to use. You can modify your page code to read:
Page:
#model TestItemDisplayList
#{ ViewBag.Title = "Items"; Layout = "~/Views/Shared/_Layout.cshtml"; }
#Html.DisplayFor(model => Model,"TestItemDisplayList")
Display Template for TestItemDisplayList
#model TestItemDisplayList
#* You could limit this loop to the first 4 items *#
#foreach(var item in model.Items){ #Html.DisplayFor(item => item) }
Display Template for TestModel
#model TestModel
<div class="item-display">
<img src="#Url.Action("GetImage", "Image", new { id = Model.ItemName})" height="150"/>
<div class="editor-label">#Html.LabelFor(model => model.PropertyHere)</div>
</div>
I assume that your URL for the image used the default route of {controller}/{action}/{id} so I used the Url.Action and specified your ID.
You could also get away witout using a DisplayTemplate for "TestItemDisplayList" and moving that code in to your page but I wasn't clear if you wanted to add logic in that to limit the number of pages.

Dynamic Layout for Error View in ASP.Net MVC

I have two action called "a" and "b". also I have two view for them. the layout of these views is difference.
for a:
#{
Layout = "~/Views/Shared/_X.cshtml";
}
for b:
#{
Layout = "~/Views/Shared/_Y.cshtml";
}
also the Error view is shared.
How can I use a dynamic layout for Error view. for example when an error occurred while processing action "a" the error show in layout of action "a" and if an error occurred while processing action "b" the error show in layout of action "b"?
You could write a helper method:
public static string GetLayout(this HtmlHelper htmlHelper)
{
var action = htmlHelper.ViewContext.RouteData.GetRequiredString("action");
if (string.Equals("a", action, StringComparison.OrdinalIgnoreCase))
{
return "~/Views/Shared/_X.cshtml";
}
else if (string.Equals("b", action, StringComparison.OrdinalIgnoreCase))
{
return "~/Views/Shared/_Y.cshtml";
}
return "~/Views/Shared/_Layout.cshtml";
}
and then:
#{
Layout = Html.GetLayout();
}
How about this overload?
Controller.View Method (String, String) (System.Web.Mvc)
in a action
return View(viewName,"_X");
in b action
return View(viewName,"_Y";
hope this help u....various way of rendering layouts in Asp.Net MVC.
Method 1 : Control Layouts rendering by using _ViewStart file in the root directory of the Views folder
We can change the default rendering of layouts with in _ViewStart file by using the below code:
#{
var controller = HttpContext.Current.Request.RequestContext.RouteData.Values["Controller"].ToString();
string layout = "";
if (controller == "Admin")
{
layout = "~/Views/Shared/_AdminLayout.cshtml";
}
else
{
layout = "~/Views/Shared/_Layout.cshtml";
}
Layout = layout;
}
Method 2 : Return Layout from ActionResult
We can also override the default layout rendering by returning the layout from the ActionResult by using the below code:
public ActionResult Index()
{
RegisterModel model = new RegisterModel();
//TO DO:
return View("Index", "_AdminLayout", model);
}
Method 3 : Define Layout with in each view on the top
We can also override the default layout rendering by defining the layout on the view by using the below code:
#{
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
thanks
You could try and pass the layout from the controller action: set the current layout in the session and then retrieve it in your error controller and pass it to the view through the ViewBag property:
public ActionResult A()
{
// Do things
// Set the layout
Session["currentLayout"] = "~/Views/Shared/_X.cshtml";
return View();
}
ErrorController:
public ActionResult NotFound() // 404
{
// Set the layout
ViewBag.ErrorLayout = Session["currentLayout"];
return View();
}
then in your error view:
#{
Layout = ViewBag.ErrorLayout;
}
I'll grant you this will not win a beauty prize; there might be other ways.
For example, take a look at this answer for how to set the layout in an ActionFilter: How to set a Razor layout in MVC via an attribute filter?
You could write your own Error Filter inheriting from HandleError and set the layout in there.

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