I have a partial view which I want to display a different type of HTML element based on a property of the model. The solution I've come up with is:
#if (Model.Element == "span")
{
<span>
Some stuff
</span>
}
else if (Model.Element == "p")
{
<p>
Some stuff
</p>
}
else
{
<div>
SomeStuff
</div>
}
This is obviously not very extensible. I'd like to write something like:
<#Model.Element>
Some stuff
</#Model.Element>
but it doesn't seem to be allowed. Is there any way to do something like this.
(I appreciate that this goes somewhat against the grain of MVC as the model and therefore the controller is specifying HTML. Actually, the element type comes from the parent view, so I think this is okay.)
Many thanks in advance.
#Html.Raw("<" + Model.Element + ">")
Some Stuff
#Html.Raw("</" + Model.Element + ">")
Is about as simple as possible. Though you could always use the TagBuilder:
#{
TagBuilder tb = new TagBuilder(Model.Element);
tb.InnerHtml = "Some Stuff";
#Html.Raw(tb.ToString())
}
Related
I have this code on a view:
#{
string x = "whatever";
}
and then I'm trying to define a helper function:
#helper MyHelper() {
<div class="whatever" #x>
</div>
}
but, apparently, #x "does not exist in the current context"... how do I access it?
Set it as parameter to MyHelper():
#helper MyHelper(string x) {...
Something useful here:
http://weblogs.asp.net/scottgu/asp-net-mvc-3-and-the-helper-syntax-within-razor
Here is part of my Index view:
#if (TempData["SucessAlert"] != null)
{
Html.RenderPartial("~/Views/Shared/_SuccessAlert.cshtml");
}
Here is the partial view, _SuccessAlert.cshtml:
<div class="alert alert-success alert-dismissable">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
#TempData["SuccessAlert"]
#TempData["SuccessAlertLinkText"]
</div>
Here is part of my controller:
TempData["SuccessAlert"] = "Successfully created account code " + mergedCode + ".";
TempData["SuccessAlertLinkText"] = "Click here to view it.";
TempData["SuccessAlertLink"] = "/AccountCode/Details?Division=" + viewModel.Division
+ "&ProgramCode=" + viewModel.ProgramCode
+ "&ProjectCode=" + viewModel.ProjectCode
+ "&includeDisabled=False&page=1";
return RedirectToAction("Index");
Everything worked fine until I added the #if() statement to the view. Apparently TempData["SuccessAlert"] is always null when this #if statement is checked. Actually, if I change the #if() statement to #if(true), it still works, so TempData has the correct values inside the partial view, even though it's null in view itself.
Any idea what I'm doing wrong? (I'm using MVC5, if that matters.)
Bah! I just realized I misspelled "Success" as "Sucess" (one "C") in the #if() statement. I'm going to leave this here to document the fact that I am an idiot, as well as on the off chance that someone else will find this lesson useful -- double-check the spelling of TempData and ViewBag keys.
I have converted my MVC3 application to MVC5, I had to change all views to razor. Having a challenge with a select list:
In ASPX view that works I am using the following:
<select id="Profession" name="Profession" style="width: 235px; background-color: #FFFFCC;">
<% List<string> allProfessions = ViewBag.AllProfessions;
string selectedProfession;
if (Model != null && !String.IsNullOrEmpty(Model.Profession))
selectedProfession = Model.Profession;
else
selectedProfession = allProfessions[0];
foreach (var aProfession in allProfessions)
{
string selectedTextMark = aProfession == selectedProfession ? " selected=\"selected\"" : String.Empty;
Response.Write(string.Format("<option value=\"{0}\" {1}>{2}</option>", aProfession, selectedTextMark, aProfession));
}%>
</select>
In Razor I am using:
<select id="Profession" name="Profession" style="width: 235px; background-color: #FFFFCC;">
#{List<string> allProfessions = ViewBag.AllProfessions;
string selectedProfession;}
#{if (Model != null && !String.IsNullOrEmpty(Model.Profession))
{selectedProfession = Model.Profession;}
else {selectedProfession = allProfessions[0];}
}
#foreach (var aProfession in allProfessions)
{
string selectedTextMark = aProfession == selectedProfession ?
"selected=\"selected\"" : String.Empty;
Response.Write(string.Format("<option value=\"{0}\" {1}>{2}</option>",
aProfession, selectedTextMark, aProfession));
}
</select>
The list shows up at the top of the page, I can't figure out where is the problem. Would appreciate your assistance.
Don't create your dropdown manually like that. Just use:
#Html.DropDownListFor(m => m.Profession, ViewBag.AllProfessions, new { style = "..." })
UPDATE
I tried your solution but got this error: Extension method cannot by dynamically dispatched
And, that's why I despise ViewBag. I apologize, as my answer was a little generic. Html.DropDownList requires the list of options parameter to be an IEnumerable<SelectListItem>. Since ViewBag is a dynamic, the types of its members cannot be ascertained, so you must cast explicitly:
(IEnumerable<SelectListItem>)ViewBag.AllProfessions
However, your AllProfessions is a simple array, so that cast won't work when the value gets inserted at run-time, but that can be easily fixed by casting it to a List<string> and then converting the items with a Select:
((List<string>)ViewBag.AllProfessions).Select(m => new SelectListItem { Value = m, Text = m })
There again, you see why dynamics are not that great, as that syntax is rather awful. The way you should be handling this type of stuff is to use your model or, preferably, view model to do what it should do: hold domain logic. Add a property to hold your list of profession choices:
public IEnumerable<SelectListItem> ProfessionChoices { get; set; }
And then, in your controller action, populate this list before rendering the view:
var model = new YourViewModel();
...
model.ProfessionChoices = repository.GetAllProfessions().Select(m => new SelectListItem { Value = m.Name, Text = m.Name });
return View(model);
repository.GetAllProfessions() is shorthand for whatever you're using as the source of your list of professions, and the Name property is shorthand for how you get at the text value of the profession: you'll need to change that appropriately to match your scenario.
Then in your view, you just need to do:
#Html.DropDownListFor(m => m.Profession, Model.ProfessionChoices)
Given that you don't have this infrastructure already set up, it may seem like a lot to do just for a drop down list, and that's a reasonable thing to think. However, working in this way will keep your view lean, make maintenance tons easier, and best of all, keep everything strongly-typed so that if there's an issue, you find out at compile-time instead of run-time.
I believe it's happening because of the Response.Write. Try this:
#Html.Raw(string.Format("<option value=\"{0}\" {1}>{2}</option>", aProfession,
selectedTextMark, aProfession))
I have a search webpage where user's can filter the search results by a person's ethnicity, as a checkbox group. There are 12 'ethnicity' checkboxes. The params get passed into g:paginate as the following, so that the user can page through the results and preserve what was checked in the ethnicity checkboxes:
<g:paginate controller="search" action="list" total="${resultCount}" params="${params}"/>
What gets output for the links includes a bunch of unnecessary data for each built URL:
2
I'd like the pagination link URLs to be output without all the extra _ethnicity variables that get passed back in the original search post:
2
How can I get the params into the paginate tag without all the extra unnecessary fields? Functionally it works, but the URLs for the paginate get requests are too long and look hideous.
Try this..,.
<g:paginate controller="search" action="list" total="${resultCount}" params="${params.findAll { it.key == 'ethnicity' && it.value }}"/>
it gives you
2
One of the dirty way to achieve what you want is
<g:paginate controller="search" action="list" params="${
params.findAll { a ->
if (a.value instanceof Collection) {
def c = a.value.findAll { b ->
return b
}
if (c) {
return c
}
} else {
return a.value
}
}
}"/>
EDIT:
spock99 answer is much better than mine, one more way is
params="${params.findAll { !it.key.toString().startsWith("_") }}"
Per the previous user, this works to filter out the extra fields, though it is ugly.
params="${params.findAll { a ->
if (!a.key.toString().startsWith("_")) {
return a.value
}
}
}"
EDIT:
Actually a cleaner way is to put this in the controller:
params.keySet().asList().each { if (it.toString().startsWith("_")) params.remove(it) }
Then in the g:paginate you can stick with
params="${params}"
I'm trying to learn Razor but have come up against a syntax problem. When I run the following code:
#if (searchTerm != ""){
<h2>Showing #ExamineManager.Instance.Search(searchTerm, true).Count() results for #searchTerm</h2>
<div class="search-results">
#foreach (var result in ExamineManager.Instance.Search(searchTerm, true)) {
if (result.Fields["nodeTypeAlias"] == 'File'){
<p>File</p>
}else{
<p>Not file</p>
}
}
</div>
}
this errors, saying "Too many characters in character literal". The actual mechanism of the code works, it's just a syntax problem with the way the conditionals are nested I think, but I've tried various combinations of #{} blocks and prepending # to various lines but just can't get it to work.
Can anyone see what I'm doing wrong?
Thanks!
'File' is invalid syntax. You probably meant "File" in your if condition when you want to work with strings:
if (result.Fields["nodeTypeAlias"] == "File")
That is because you've got comparison
result.Fields["nodeTypeAlias"] == 'File'
In c#, you cannot write strings into single quotes like that. You should change it into
result.Fields["nodeTypeAlias"] == "File"
Just change the Code In this way
#{
if (searchTerm != ""){
<h2>Showing #ExamineManager.Instance.Search(searchTerm, true).Count() results for #searchTerm</h2>
<div class="search-results">
foreach (var result in ExamineManager.Instance.Search(searchTerm, true)) {
if (result.Fields["nodeTypeAlias"] == 'File'){
<p>File</p>
}
else{
<p>Not file</p>
}
}
</div>
}
}
THis code will help you