For example,
sortDir field is passed to model, but if I forget it, I want to use asc as default one.
This does not work as it shows div only when sortDir==null.
<div class="wrapper"
th:if="${sortDir == null}" th:with="sortDir=${'asc'}">
// Main content
</div>
You should remove your conditional on the div and try to decide on the value with an inline expression as follows:
<div class="wrapper"
th:with="sortDir=${sortDir != null} ? sortDir : 'asc'">
// Main content
</div>
Another way to achieve this is by setting the value right in the controller before you return from the controller method. An example line might be as follows:
#GetMapping
public String getSomething(Model model) {
if (sortDir == null) { sortDir = "asc" };
model.addAttribute("sortDir", sortDir);
return "someView";
}
Related
Im reading a Y/N value from my model in a razor for loop.
I want to change the value from Y/N to true/false.
<td>#Html.CheckBoxFor(modelItem => (item.ReqDowngrade == "Y" ? true : false))</td>
I keep geting this error: System.InvalidOperationException: 'Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.'
Is there any way I can do this without creating a server view model?
This declaration is totally wrong:
#Html.CheckBoxFor(modelItem => (item.ReqDowngrade == "Y" ? true : false))
CheckBoxFor helper only accepts viewmodel properties with either bool or Nullable<bool> type for model binding, hence the conditional expression above should not be used. If you want to assign Y or N value to a new bool viewmodel property bound with CheckBoxFor, do this instead:
Viewmodel
// assumed both 'ReqDownGrade' & new bool property are in same viewmodel class
public bool CheckReqDownGrade
{
get
{
// returns false if ReqDownGrade is 'N'
return (ReqDownGrade == "Y");
}
set
{
CheckReqDownGrade = value;
CheckReqDownGrade == true ? ReqDownGrade = "Y" : ReqDownGrade = "N";
}
}
View
#Html.CheckBoxFor(model => model.CheckReqDownGrade)
If you still insist to not adding bool viewmodel property, you can use a HiddenFor, standard HTML input element with type="checkbox" attribute and simple JS trick:
View
#Html.HiddenFor(modelItem => item.ReqDowngrade, new { id = "ReqDownGrade" })
<input id="CheckReqDownGrade" type="checkbox" #(item.ReqDowngrade == "Y" ? "checked='checked'" : "") />
JS (jQuery)
<script>
$(function() {
$('#CheckReqDownGrade').click(function() {
var isChecked = $(this).is(':checked');
$('#ReqDownGrade').val(isChecked ? 'Y' : 'N');
});
});
</script>
I have a partial view on my mvc page. The view is rendered by default with no data, but will be updated based on a value selection from a combobox in another section of the page. The partial view takes an id as a parameter which it will use to get the data needed to return the model.
The problem that I am having is that on the initial load, the parameter is null since nothing has been selected and I am getting a null value exception.
Is there a way that I can use an if statement in a direct events call to check the selected item and return 0 is that is null?
See me sample code below for clarification.
Thanks
Here are the relevant parts of my main page (index.cshtml) -
x.ComboBox()
.ID("MyCombo")
.DisplayField("Title")
.ValueField("Number")
.TypeAhead(false)
.Width(500)
.PageSize(10)
.HideBaseTrigger(true)
.MinChars(0)
.TriggerAction(TriggerAction.Query)
.DirectEvents(de =>
{
de.Select.Url = Url.Action("MyPartial");
#* Can I use an if statment here to check the selected item's value? *#
de.Select.ExtraParams.Add(new { id = App.MyCombo.getValue() });
})
.ListConfig(Html.X().BoundList()
.LoadingText("Searching...")
.ItemTpl(Html.X().XTemplate()
.Html(#<text>
<div class="search-item">
<h3><span>{Number}</span>{Title}</h3>
{Description}
</div>
</text>)
)
)
........
#Html.Partial("MyPartial", Model.MyPartialVM)
and here is my controller code -
public ActionResult MyPartial(string id)
{
var vm = new MyPartialViewModel
{
Number = id,
Title = "New Title"
};
ViewData.Model = vm;
var pvr = new Ext.Net.MVC.PartialViewResult
{
ViewData = this.ViewData
};
return pvr;
}
This works if I hardcode a parameter value, but not if I try it as it is now. Here is the error I get -
Message=Cannot perform runtime binding on a null reference
So I was thinking that I can do an if in teh DirectEvents piece to check for a null on the combobox selection, I can inject a 0 when necessary and handle that in the controller. Can this be done?
Try if this works:
x.ComboBox()
.ID("MyCombo")
.DisplayField("Title")
.ValueField("Number")
.TypeAhead(false)
.Width(500)
.PageSize(10)
.HideBaseTrigger(true)
.MinChars(0)
.TriggerAction(TriggerAction.Query)
.DirectEvents(de =>
{
de.Select.Url = Url.Action("MyPartial");
de.Select.ExtraParams.Add(new {
Name = "id",
Value ="App.MyCombo.getValue() == null ? '0' : App.MyCombo.getValue()",
Mode = ParameterMode.Raw
});
})
.ListConfig(Html.X().BoundList()
.LoadingText("Searching...")
.ItemTpl(Html.X().XTemplate()
.Html(#<text>
<div class="search-item">
<h3><span>{Number}</span>{Title}</h3>
{Description}
</div>
</text>)
)
)
I had in my classes some fields that represents true or false, but it has string values "T" or "F".
How to bind the checkbox to these fields?
You can do this in ASP.Net MVC Razor
<input type="checkbox" name="someName" value="#Model.SomeValue"
#(Model.IsChecked == "T" ? "checked='checked'" : "") />
However, this may not be what you are looking for, since you would have to do some manual work on the server to figure out values that had been "unchecked".
By default only your checked values will get sent to the server.
UPDATE:
The Html.CheckBox and Html.CheckBoxFor helper methods both emit hidden fields in order to make sure everything binds correctly back to your model. You can imitate this behavior pretty easily.
First you need to emit a hidden field that will be bound to your model on the server.
#Html.HiddenFor(model => model.StringBool, new { id = "_stringBool" })
Next you create a plain jane checkbox and set the initial state to reflect your model.
<input type="checkbox" id="myCheckBox" #(Model.StringBool == "T" ? "checked='checked'" : "") />
This checkbox's only purpose is to proxy values to and from the hidden field so your model will automatically get bound on the server. This can be achieved with some simple jQuery.
$("#myCheckBox").click(function () {
var isChecked = $(this).is(":checked");
$("#_stringBool").val(isChecked ? "T" : "F");
});
Now checking and unchecking the box will set the value of your bound hidden field accordingly. When you post to the server your values will be preserved via model binding.
Some things to note
This does not take into account validation. It is very easy to change the value of the hidden field so make sure you properly validate on the server side!
When you set the checkstate of the new checkbox items, just put an if statement:
checkBox1.Checked = (stringValue == "T") ? true : false;
I made my own extension to solve this problem. It is a little tidyer in the razorview, helps minimizing the c# / razor mixture. Here's the class:
public static class CheckBoxExtensions {
public static MvcHtmlString ValueCheckbox<TModel>(this HtmlHelper<TModel> htmlHelper, string name, string value, bool isChecked, IDictionary<string, object> htmlAttributes, bool disabled = false)
{
string result = string.Format(CultureInfo.InvariantCulture,
"<input type=\"checkbox\" name=\"{0}\" value=\"{1}\" {2} {3} ",
name, value, (isChecked) ? "checked=\"checked\"" : "", (disabled) ? "disabled=\"disabled\"" : "");
if (htmlAttributes != null && htmlAttributes.Count > 0)
{
foreach (KeyValuePair<string, object> item in htmlAttributes)
{
result += string.Format(CultureInfo.InvariantCulture, "{0}=\"{1}\" ", item.Key, item.Value.ToString());
}
}
result += " />";
return new MvcHtmlString(result);
}
}
And this is what I do in the razorview:
Html.ValueCheckbox("SelectedItems",
item.Number,
(Model.SelectedItems.Contains(item.Number)),
new Dictionary<string, object>() {
{ "data-disable-bubble", "true" },
{ "data-forms-enable-any-checked-checkbox", "true" }
}
)
Dont mind the weir HtmlAttributes, I figured I would just let them in there :-)
I want to define this section only if some property (Model.ReadOnly) is false.
#section toolbar {
<div class="tool">
<div class="row">
#Html.ActionLink( Resources.Strings.Edit, "Edit", "Profile" )
</div>
<div class="row">
#Html.ActionLink( Resources.Strings.Delete, "Delete", "Profile" )
</div>
</div >
}
I tried wrapping it up in #if ( !Model.ReadOnly ) {} but it doesn't work.
Is there a way to do this?
I do not want to define an empty section (as #itsmatt suggests), the layout of my page changes whether the section is defined or not (using IsSectionDefined( "toolbar" )).
This should work.
#if (!Model.ReadOnly)
{
<text>
#section toolbar {
}
</text>
}
I never said it would be pretty ;-)
This works for me:
#section SomeSection {
#if (!Model.ReadOnly)
{
}
}
Essentially flipping where the conditional is. This essentially results in an empty section if Model.ReadOnly is true.
Update:
So, what about moving that section to a PartialView and doing something like:
#Html.Partial("MyAction")
in your View and then let the MyAction return you the appropriate PartialView based on the ReadOnly value? Something like:
public PartialViewResult MyAction()
{
...
// determine readonly status - could have passed this to the action I suppose
if (ReadOnly)
{
return PartialView("TheOneThatDefinesTheSection");
}
else
{
return PartialView("TheOneThatDoesNotDefineTheSection");
}
}
Seems like that would work just fine.
Bertrand,
See:
Razor If/Else conditional operator syntax
basically (para-phrasing), ... Razor currently supports a subset of C# expressions without using #() and unfortunately, ternary operators are not part of that set.
also, this may be a way around the issue:
conditional logic in mvc view vs htmlhelper vs action
basically, use the if logic to call a partialview to satisfy your criteria.
[edit] this was my basic thinking (where your #section code is defined in that partial):
#if(!Model.ReadOnly)
{
#Html.Partial("toolbar")
}
Let's say I've the below marks up obtained by using values of some Model's properties:
<div id = "tabs">
<ul>
<%foreach(var category in Model.Categories){%>
<li>category.Name</li>
<%}%>
</ul>
<%foreach(var category in Model.Categories){%>
<div id = "category.Name">
//Content for each category goes here....
</div>
<%}%>
</div>
Using JQuery I'm able to create easily a tabs widget
$("#tabs").tabs();
The Model contains also a property called ListOfListArticle, which is a list of a list of articles. Articles in the inner-list are grouped by category. There's also an other property called ArticleToDisplay.
public List<List<Articles>> ListOfListArticle { get; set; }
public Article ArticleToDisplay { get; set; }
public List<Category> Categories { get; set; }
I'd like to check first the category to which the article to display belongs and be able to automatically select the tab corresponding to that category. For now, when the page loads, the first tab is always selected.
Any way to deal with this?
Thanks for helping.
$("#tabs").tabs(
{ selected: <%=Model.Categories.IndexOf(Model.ArticleToDisplay.Category) %> }
);
might be better to make that a property on your Model
public int Index
{
get
{
if (Categories == null || ArticleToDisplay == null || ArticleToDisplay.Category == null)
return 0;
return Categories.IndexOf(ArticleToDisplay.Category);
}
}
then you can just write:
$("#tabs").tabs(
{ selected: <%=Model.Index %> }
);
I had same requirement.
I used a hidden field and then JS to get that value to set the jquery ui tab
1) I put a hidden field on the form ...
<%: Html.HiddenFor(model => model.EnmCreateCaseTab) %>
2) I have a javascript code bespoke for the page, which wraps js for the whole page, hence at the top of the page I have
<script type="text/javascript">
Sys.onReady(function () {
var page = MyApp.newMyPage();
page.Setup();
});
</script>
( This is javascript classes in the style of Douglas Crockford ... )
Either the ctor or the page.Setup() fn then calls a private fn that gets the value of the hidden control and sets the tab with javascript
var SelectInitiallySelectedTab = function () {
var formValueEnmCreateCaseTab = $("#EnmCreateCaseTab").val();
// ...
// set a jquery tabs control
SelectTab(tabNum);
}
var SelectTab = function (tabNum) {
// ensure tabNum is in bounds
var tabCount = TabCount();
var maxTabIndex = tabCount - 1;
tabNum = tabNum < 0 ? 0 : tabNum;
tabNum = tabNum > maxTabIndex ? maxTabIndex : tabNum;
$('#tabs').tabs({ selected: tabNum });
}
The hidden field, can be used to retain the user selected tab across re-submits ...
just add ui-tabs-selected class to intended <li> element.
for details see following stack overflow page
Opening page with tab preselected that's not the first tab