I'm trying to dynamically add a class to a div in an MVC View; in this case error. I find myself creating a Razor If-Else block which means my view has lots of duplicated code. I have tried a few differant Razor scenario's but can't find a reasonable way to conditionally append new classes. Can anyone suggest an approach that avoids duplicating code and keeps View decisions in the View.
#if (ViewData.ModelState["Title"] != null && ViewData.ModelState["Title"].Errors.Any())
{
<div class="select error">
#Html.DropDownListWithTooltipFor(m => m.Title, Model.Titles, new { required = string.Empty, #class = "sel" })
</div>
}
else
{
<div class="select">
#Html.DropDownListWithTooltipFor(m => m.Title, Model.Titles, new { required = string.Empty, #class = "sel" })
</div>
}
Try this:
<div #(condition ? "class=select error" : "class = select">
</div>
Razor will add the quotes for you (class = "select error"). This should work in MVC3.
Also, take a look at: Conditional HTML Attributes using Razor MVC3 and MVC3 - Conditionally add id element with Razor (actually pretty much duplicates)
Note the answer of Erik Porter: If you can do it with MVC4, then there's a more elegant way:
<div class="#yourClass" />
Related
i want to declare a local variable in my razor html form (view) and want to store user input value in that local variable.And then want to use that variable in foreach loop .in mvc 5 i am new to asp.net.
#using (Html.BeginForm("AddQuestion", "admin", new { id = ViewBag.qf_id }, FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-group">
<label>Question Statement</label>
#Html.TextBoxFor(a => a.Ques.QuestionString, new { #class = "form-control" })
#Html.ValidationMessageFor(a => a.Ques.QuestionString)
</div>
<div class="form-group">
<label>No. of option you want to add for this question </label>
<div class="col-md-4">
#{var val = #Html.TextBoxFor(a => a.counter, new { #class = "form-control" }); }
</div>
</div>
foreach(var item in val)
{
#Html.TextBoxFor(a=>a.Ans.AnswerStatement)
}
<div>
<button class="btn btn-primary" type="submit">Add</button>
</div>
}
What you are trying to do won't work unless it gets adapted to 1 of 2 solutions:
1) The only way this works is if the use enters a value in the textbox, then posts back to the controller, and the controller inputs this variable into the model, which the view then re-renders, using the number in the model, with the desired number of entries. That's the web forms way and is inefficient.
2) Using JavaScript, when a user enters a number, JavaScript can either render the markup using a templating framework, or make a request to the server, get the individual data, and return a partial view as HTML.
I just started using umbraco 4 days ago and I'm stuck with this problem.
I have a page named "About Us" that is a child under "Home" and I need to get some of its properties in the "Home" Page.
I created a partial view macro to do this but I get the error loading partial view script instead.
Below is my code:
#{ var selection = CurrentPage.Children.Where(x => x.Name == "aboutus"); }
#if (selection.Any())
{
<ul>
#foreach (var item in selection)
{
<div class="sc-inner">
<h4>
#item.PageTitle</h4>
<p>
#Umbraco.Truncate(#item.mainAboutDescription, 100)</p>
<a class="btn btn-danger" href="#item.Url">Read More...</a>
</div>
break;
}
</ul>
}
Can someone please tell me what I'm doing wrong?
Thanks in advance.
Edits:
The error on the website I got is below;
Error loading Partial View script (file: ~/Views/MacroPartials/homePage_aboutUsSection.cshtml)
Assuming the partial is inheriting UmbracoTemplatePage the CurrentPage property is a dynamic, you cannot use lambda expressions as an argument to a dynamically dispatched operation.
If you wish to use Linq to query the content use Model.Content rather than CurrentPage which is an IPublishedContent e.g.
#{ var selection = Model.Content.Children.Where(x => x.Name == "aboutus"); }
Note: the Name property will return the documents Name as entered in the CMS most likely 'About Us' instead of 'aboutus'
Using the about will return an IEnumerable<IPublishedContent> so you will need to use the GetPropertyValue method rather than accessing the content dynamically:
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{ var selection = Model.Content.Children.Where(x => x.Name == "aboutus"); }
#if (selection.Any())
{
<ul>
#foreach (var item in selection)
{
<li class="sc-inner">
<h4>
#item.GetPropertyValue("pageTitle")
</h4>
<p>
#Umbraco.Truncate(#item.GetPropertyValue<string>("mainAboutDescription"), 100)
</p>
<a class="btn btn-danger" href="#item.Url">Read More...</a>
</li>
break;
}
</ul>
}
Very bad practice to use the Name property for querying in your code - what if somebody changes the Name to About for example. Your code would break. If there is something else that is unique on the node then it would be better.
For example if you have an aboutUs document type for your about us page you could use:
Model.Content.Children.Where(x => x.DocumentTypeAlias == "exactNameOfYourDocTypeAliasHere")
or, although not so robust, the Id of the page could be used.
Model.Content.Children.Where(x => x.Id == 1234)
The Id is far less likely to change than the Name of a key page like this.
I would generally not use the Id in code either but it is far better than Name
I have a web page that dynamically creates components by rendering them through a RenderPartial Html Helper like this
Html.RenderPartial("_UploadStaticField", config);
Within the config object is a field called 'isUnderReview'. When this is set to true the components should be disabled by using the code below
//Single selection
<div class="editor-section">
<div class="label">
#Html.DisplayEditLabel(Model.Label, Model.Required.Value)
</div>
<div class="field large-text-field">
#Html.DropDownListFor(m => m.SelectedListOptionID, new SelectList(Model.ListOptions, "ID", "Name", Model.SelectedListOptionID).OrderBy(l => l.Value), new Dictionary<string, object>{
{"id", "staticField_" + Model.ID}})
</div>
</div>
<script>
$(document).ready(function () {
if ("#Model.IsUnderReview" == "True") {
document.getElementById("staticField_" + "#Model.ID").disabled = true;
}
});
</script>
and..
//Multiple selection
<div class="editor-section">
<div class="label">
#Html.DisplayEditLabel(Model.Label, Model.Required.Value)
</div>
<div class="field large-text-field">
#Html.ListBoxFor(x => x.SelectedRoles, filetypes, new { #class = "multiselectFileTypes" , id = "staticFieldM_" + Model.ID})
</div>
</div>
#Scripts.Render(BundleConfig.Scripts_MultiSelect)
<script>
$(document).ready(function () {
if ("#Model.IsUnderReview" == "True") {
document.getElementById("staticFieldM_" + "#Model.ID").disabled = true;
}
});
</script>
The code works to the point that the methods run but the components are still able to be used. Is there a way of cancelling any users selections which will serve as disabling as the values wont change?
Scripts should never be in partials (you potentially generating multiple inline scripts that may cause other problems, especially with the bundle). However a script is not even necessary for this, you can use a simple if statement or conditional attributes to generate what you want.
When you say "but the components are still able to be used", I'm guessing that your using a plugin to generate controls as suggested by Scripts.Render(BundleConfig.Scripts_MultiSelect) which will be hiding the original <select> element and generating its own html which is why it still interactive.
But the next problem is that disabled controls do not post back a value, so the vales of SelectedListOptionID and SelectedRoles will be their default, possibly resulting in your app failing depending on the code in your POST method.
Move the #Scripts.Render() into you view or layout, delete the scripts to disable the element and then change the partial to
#if(Model.IsUnderReview)
{
#Html.HiddenFor(m => m.SelectedListOptionID) // if you want the value to be posted
// add an element to display the Name associated with the SelectedListOptionID
// if necessary, for example your view model might include a property
// string SelectedListOptionName
}
else
{
#Html.DropDownListFor(m => m.SelectedListOptionID, new SelectList(Model.ListOptions, "ID", "Name").OrderBy(l => l.Value))
}
Side notes:
There is no reason to add you own id attribute (the
DropDownListFor() method generates <select
id="SelectedListOptionID" ... >
Remove the last parameter of the SelectList constructor
(Model.SelectedListOptionID) - its ignored by the
DropDownListFor() method. I also recommend your model contains an IEnumerable<SelectListItem> OptionsList property and you populate that in the controller so that it can simply be #Html.DropDownListFor(m => m.SelectedListOptionID, Model.OptionsList)
In my view I have,
#Html.CheckBoxFor(m => m.IsExist, new { #id = "IsExist" })
In my Model I have IsExist value from DB. Either true or false.
Now how can I 'Check' or 'Uncheck' the option, based on the true or false value in IsExist.
I expected, on binding by default the check box takes the value of Model. Howeverr that is not happening.
How can i achieve it?
Here how i achieved it
#Html.CheckBox("VC",(item.isVC=="Y") ? true : false)
where my item.isVC has value "Y" or "N"
Below snippet indicates an alternate way of having checkbox created and conditionally making it checked/unchecked. The following approach is also useful to get the value of checkbox by traditional approach using jquery.
#model myproject.Models.StudentModel
<div class="row">
<label class="checkbox-inline">
<input type="checkbox" name="selfStudy" checked="#Model.IsExist"><b>Self Study</b>
</label>
</div>
You can do this to check a checkbox :
if (Model.IsExist) {
#Html.CheckBoxFor(m => m.IsExist, new { #id = "IsExist", "checked" = "checked"})
}
Hope it's help
In my controller I use the following:
ViewBag.ReferenceId = new SelectList(_reference.Get("00")
.AsEnumerable()
.OrderBy(o => o.Order), "RowKey", "Value", "00");
Then in my view I use the following extension to create a dropdown:
#Html.DropDownList("ReferenceID",
null,
new {
id = "ReferenceID",
#class = "combobox2",
style="width: 150px;"
}
)
Now I would like to change this to create an unordered list. Something like the following:
<ul id="categories" class="pane list">
<li>Websites</li>
<li>Web Design</li>
<li>Print</li>
</ul>
Is there any MVC extension that can do this for me or is there an easy way I can code something?
There is no equivalent, though you could write it on your own like this:
tagsList = "<ul>{0}</ul>";
tagsListItem = "<li>{0}</li>";
StringBuilder result = new StringBuilder();
list.ForEach(listItem => result.AppendFormat(tagsListItem, item.ToString()));
return string.Format(tagsList, result.ToString());
And you could fit the code for your needs (like adding additional tags, attributes etc.)
Write your HtmlHelper http://www.asp.net/mvc/tutorials/older-versions/views/creating-custom-html-helpers-cs but the best ways is to browse MVC source code and learn http://aspnet.codeplex.com/SourceControl/changeset/view/72551#288014 or use a foreach.
<ul id="categories" class="pane list">
#foreach(var category in categories)
{
<li>#category</li>
}
</ul>
Regards