I am currently using Glass Mapper to map items in the sitecore tree to Model classes in C#, however I am having issues when trying to read the Checked parameter of a checkbox field on the item.
How do I read the Checked property? I have tried setting the field below to a CheckboxField data type but it has still failed to load the data I require.
Will I need to create another Model class to extract the CheckboxField template data values?
The class property definition
[SitecoreField("Is Gold Class Package")]
public virtual CheckboxField IsGoldClassPackage { get; set; }
The Razor markup
#foreach (var package in Model.LoyaltyPackages.LoyaltyPackageDataItems)
{
<div vrewards-item title="#package.Title" unlocked price="#package.Points" icon="#package.Icon"
#(package.IsGoldClassPackage.Checked == true ? goldClassAttrribute : "") >
</div>
}
In Glass you don't map the fields but just the values. So your domain model should look like this:
[SitecoreField("Is Gold Class Package")]
public virtual bool IsGoldClassPackage { get; set; }
And in your view you can simply get the value from the model:
#foreach (var package in Model.LoyaltyPackages.LoyaltyPackageDataItems)
{
<div vrewards-item title="#package.Title" unlocked price="#package.Points" icon="#package.Icon"
#(package.IsGoldClassPackage == true ? goldClassAttrribute : "") >
</div>
}
Related
Problem description
I'm currently working on a Wizard mechanism in our ASP.NET MVC application. However, I've faced a problem while trying to bind model in the view. In short:
I've got a wizard model which looks more or less like this:
class WizardViewModel {
public IList<StepViewModel> Steps { get; set; }
// ...
}
Each step except for last has got its own model. The last step (summary) takes whole WizardStepModel and is used only to display data (via disabled controls). Displaying values from all steps leads to this kind of code in the view:
#Html.DropDownListFor(
m => ((ConcreteStepModel)Model.Steps[0]).SelectedValue,
((ConcreteStepModel)Model.Steps[0]).SelectList,
new { disabled = "disabled" }
)
The code works, but continuous casting base step model to a concrete class only to get the value:
Is uncomfortable,
makes code less readable.
What I tried to do?
I thought that I could create an alias for each step:
#{
ConcreteStepModel stepOne = (ConcreteStepModel)Model.Steps[0];
}
And then:
#Html.DropDownListFor(
m => stepOne.SelectedValue, stepOne.SelectList, new { disabled = "disabled" }
)
It works for most of controls, but not for DropDownList. For some reason, value of the dropdown is bound incorrectly and shows first option instead of the selected one.
Question
Is there another way which I could use for creating some kind of aliases for steps from the wizard so that I don't have to perform casting each time I need to get a value? Or maybe I am doing something wrong? I'd be grateful for any help.
Since your 'last step' is just a summary and presumably used as a final 'confirmation step' before saving to the database, then you should not be generating disabled form controls for your properties. It would be rendering anywhere 2-5 times the html that is necessary which will just degrade performance.
Instead just generate the value of the property as text, for example
<div class="field">
<div class="field-label">#Html.DisplayNameFor(m => m.Steps[0].SomeProperty)</div>
<div class="field-value">#Html.DisplayFor(m => m.Steps[0].SomeProperty)</div>
</div>
and use the class names to style the layout (and the result would no doubt save a lot of screen space as well).
For the dropdownlist properties, you would need to add an additional property associated with the selected text, so in addition to public int SelectedValue { get; set; } used in the edit view, you would include an associated public string SelectedText { get; set; } property for the 'final step' view.
It also appears from your code that StepViewModel is an abstract base class and you have a concrete class for each 'step'. If that is the case, then it would be better for your WizardViewModel to contain properties for each step
public class WizardViewModel
{
public Step1Model Step1 { get; set; }
public Step2Model Step2 { get; set; }
....
}
which means if you really did want to generate form controls, it would not be be necessary to cast the type. The code would just be
#Html.DropDownListFor(m => m.Step1.SelectedValue, Model.Step1.SelectList, new { disabled = "disabled" })
I have this data from database with self relation
Parent_ID Name Child_ID
1 cities null
2 Egypt 1
3 Saudi 1
4 technology null
5 vb.net 4
6 c# 4
Now i want to build html navigation bar using this data
To be like the following
<ul>
<li>cities
<ul>
<li>Egypt</li>
<li>Saudi</li>
</ul>
</li>
<li>technology
<ul>
<li>vb.net</li>
<li>c#</li>
</ul>
</li>
</ul>
I don't know what is the best way to da that
My be xml node or my be using linqu ...
Whatever the best way help me please.
you can use asp:reapeater control provide datasource to it and give html format inside it. The easiest and the efficient way.
Explore it more....
Edited: You must mention
in mvc, you can pass data inside viewBag, viewdata whatever you like and on view you can use foreach iteration and inside it generate the required html
like
ViewDate["data whatever"] = your data
and on html
#foreach(var item in ....)
{
<a href='item.whatever Value'>
}
OK, here is one method of creating a n deep menu viewmodel
grab all the data from the table with one select and populate a list of menuItemMVs. create a menuMV object and put this list in the static AllMenuItems list. create a razor view for the root of the menu and bind it to menuMV. create a partial view for a menu item which binds to menuItemVM this should contain a for loop looping through the childern and recursively calling RenderParital itself (the partial view) for each child in the menuItemVM it is rendering.
get your root menu razor to loop over the rootMenuItems and renderpartial your menuitem partial view for each
public class menuVM
{
public static List<menuItemVM> AllMenuItems { get; set; }
public IEnumerable<menuItemVM> rootMenuitems
{
get { return menuVM.AllMenuItems.Where(c => c.ParentId == null); }
}
}
public class menuItemVM
{
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get;set; }
public IEnumerable<menuItemVM> Childern {
get
{
return menuVM.Childern.Where(c => c.ParentId == this.Id);
}
}
}
ps. I think you have childId and parentId the wrong way around in your
sample data
I am fairly new to MVC, but have quite a bit of experience in development in general, and am having an issue with MVC request life cycle it seems.
Will try to keep this simple, even tho the project is a bit complex in some areas.
I have a view bound to a view model that has a few complex list properties. These properties are displayed via checkboxes who's IDs are not directly related to any property in the model, but instead related to the IDs of the objects in the List<>. Because of this, the checked values do not automatically get applied to the model on POST.
To get around that, I added code in the Action method in the controller that parses the proper controls (in the Request.Form collection) and assigns the checked/selected value to the proper list items in the model.
This works perfectly up to a point.
Now, I also use Fluent Validation, and the problem is when performing custom validation rules when posting a new model to the server. The Validation routine is firing BEFORE the controller's action method, and thus before my processing of the list objects.
So, my question is, is there a way I can override the initial call to the model validation so I can just call the validation manually after my processing? I know I can do that which will fix the problem without overriding the initial call, but some of the validation takes a bit of time to process since it requires linq queries to a live database, so I do not want the validation to fire 2 times - that will quite literally double the time it takes to return no matter if the model is valid or not.
EDIT: Adding a example:
namespace Models
{
[Validator(typeof(MemberValidator))]
public class ViewMember
{
public int MemberID { get; set; }
public short RegionID { get; set; }
public List<PropTypeInfo> PropTypes { get; set; }
}
}
PropTypeInfo class:
public class PropTypeInfo
{
public byte ID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool Selected { get; set; }
public PropTypeInfo(byte i, string n, string d, bool sel)
{
ID = i;
Name = n;
Description = d;
Selected = sel;
}
public static List<PropTypeInfo> GetAll(bool selected = false)
{
List<PropTypeInfo> output = new List<PropTypeInfo>();
OpenAccess.Context context = new OpenAccess.Context();
var list = (from f in context.Prop_Types orderby f.PropType select f).ToList();
foreach (OpenAccess.WebrentzServerPayments.Models.Prop_Type p in list)
output.Add(new PropTypeInfo(p.PropType, p.PropName, p.DisplayText, selected));
return output;
}
}
now here is the code in the view that renders the checkboxes for each item in the list:
<div class="Column Emp-PropTypes">
#foreach (WebrentzServerPayments.Models.PropTypeInfo ptype in Model.PropTypes)
{
<div style="float:right;width:20%;font-weight:bold;">
#Html.CheckBox("ptype_" + ptype.ID, ptype.Selected, new {Value=ptype.ID}) #Html.Raw(" ") #ptype.Name
</div>
}
</div>
And here is the code I use in the Controller Action method to pull that data back in to the List:
foreach (PropTypeInfo info in member.PropTypes)
info.Selected = form[string.Format("ptype_{0}", info.ID)].Contains(info.ID.ToString());
As a little background, a "PropType" is a type of property (house, condo, apartment) - there are about 2 dozen of them, and more can be added/removed at any time. The list in the class called "PropTypes" is first populated with the Name, Description and ID from a table in the database that lists all the available proptypes for that region.
We then will mark the proptypes as "selected" if the user has chosen that particular type. Those are saved to a table called Member.PropTypes (MemberID, ProptypeID).
So, at runtime the list will contain one record for each available proptype and the selected property will be set to yes if that user has selected it. That makes it easy to render the full list in the view...
Its actually quite a bit more complex as there are almost a dozen such lists, but each works the exact same way just with different data, as well as about 200 additional properties that are easier to manage. Only these lists are causing the issue.
Any help appreciated!
Dave
This is not a duplicate.Though the other question is same as this it got solved when it deviated from the procedure. Here i again stumbled upon the same question.
Iam using a DB First approach.
I have a context file called Dynaportal.context.cs, which has the class called DynaPortalEntities:-
public partial class DynaPortalEntities : DbContext
{
...
public DbSet<Page> Pages{ get; set; }
public DbSet<TemplateMaster> TemplateMasters { get; set; }
}
In view
#model DynaPortalMVC.Models.DynaPortalEntities
and in a foreach loop
#foreach (var item in Model.TemplateMasters)
{}
In the same view , I need a page model which is not iEnumerable, like this:-
#Html.EditorFor(model => model.Pages.Title)===========>This shows error under Title
So here i should convert the IEnumerable Model.Pages to a single page object to get model.pages.Title.
Yes, if I understand correctly, Razor does not know what Page you want the title for since you are asking for the Title of all Pages.
Usually, you would loop through the Pages and output each title using #foreach. Or, index into the Pages: #Html.EditorFor(model => model.Pages.First().Title).
When I am changing the "model => model.id" to "model => model.Supplierid" i am getting below error
"The parameter 'expression' must evaluate to an IEnumerable when
multiple selection is allowed."
please have look on below code
// this my model class
public class clslistbox{
public int id { get; set; }
public int Supplierid { get; set; }
public List<SuppDocuments> lstDocImgs { get; set; }
public class SuppDocuments
{
public string Title { get; set; }
public int documentid { get; set; }
}
public List<SuppDocuments> listDocImages()
{
List<SuppDocuments> _lst = new List<SuppDocuments>();
SuppDocuments _supp = new SuppDocuments();
_supp.Title = "title";
_supp.documentid = 1;
_lst.Add(_supp);
return _lst;
}
}
// this my controller
[HttpGet]
public ActionResult AddEditSupplier(int id)
{
clslistbox _lst = new clslistbox();
_lst.lstDocImgs= _lst.listDocImages();
return View(_lst);
}
// this is view where i am binding listboxfor
#model clslistbox
#using (Html.BeginForm("AddEditSupplier", "Admin", FormMethod.Post))
{
#Html.ListBoxFor(model => model.id, new SelectList(Model.lstDocImgs, "documentid", "title"))
}
Can anyone see the reason for it?
I think the changing of the property in the expression here is a red-herring - it won't work in either case.
Update
However, see at the end of my answer for some probably needlessly detailed exposition on why you didn't get an error first-time round.
End Update
You're using ListBoxFor - which is used to provide users with multiple selection capabilities - but you're trying to bind that to an int property - which cannot support multiple selection. (It needs to be an IEnumerable<T> at least to be able to bind a list box to it by default in MVC)
I think you mean to be using DropDownListFor - i.e. to display a list of items from which only one can be selected?
If you're actually looking for single-selection semantics in a listbox, that's trickier to do in MVC because it's Html helpers are geared entirely around listboxes being for multiple selection. Someone else on SO has asked a question about how to get a dropdown to look like a list box: How do I create a ListBox in ASP.NET MVC with single selection mode?.
Or you could generate the HTML for such a listbox yourself.
(Update) - Potentially needlessly detailed exposition(!)
The reason you don't get an exception first time round is probably because there was no value for id in ModelState when the HTML was generated. Here's the reflected MVC source (from SelectExtensions.SelectInternal) that's of interest (the GetSelectListWithDefaultValue call at the end is the source of your exception):
object obj =
allowMultiple ? htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof(string[])) :
htmlHelper.GetModelStateValue(fullHtmlFieldName, typeof(string));
if (!flag && obj == null && !string.IsNullOrEmpty(name))
{
obj = htmlHelper.ViewData.Eval(name);
}
if (obj != null)
{
selectList =
SelectExtensions.GetSelectListWithDefaultValue(selectList, obj, allowMultiple);
}
Note first that the control variable allowMultiple is true in your case, because you've called ListBoxFor. selectList is the SelectList you create and pass as the second parameter. One of the things that MVC (unfortunately in some cases) does is to use ModelState to modify the select list you pass when re-displaying a view in order to ensure that values which were set in ModelState via a POST are re-selected when the view is reloaded (this is useful when page validation fails because you won't copy the values to your underlying model from ModelState, but the page should still show those values as being selected).
So as you can see on the first line, the model's current value for the expression/field you pass is fished out of model state; either as a string array or as a string. If that fails (returns null)then it makes another go to execute the expression (or similar) to grab the model value. If it gets a non-null value from there, it calls SelectExtensions.GetSelectListWithDefaultValue.
As I say - what you're trying to do will ultimately not work in either the case of Id or SupplierId (because they would need to be IEnumerable) but I believe this ModelState->Eval process is yielding a null value when you use Id, so the process of getting an 'adjusted' SelectList is skipped - so the exception doesn't get raised. The same is not true when you use SupplierId because I'll wager that there's either a value in ModelState at that point, or the ViewData.Eval successfully gets an integer value.
Not throwing an exception is not the same as working!.
End update
Try changing your property from int to int[]
public class SuppDocuments
{
public string Title { get; set; }
public int documentid { get; set; }
}
Assuming above is the class used for binding the model , try changing the documentid property as below
public class SuppDocuments
{
public string Title { get; set; }
public int[] documentid { get; set; }
}