I am new to struts. I dont know exactly if my solution for my problem is correct or not.
My problem is I have two tables as shown below
I would like to create an HTML table based on the above tables, showing the fields, name of group, id of group, and name of sub group and Id of subgroup. I tried to use list and iterator. But am not able to get both the values(both name and id)
inside class
public List getName() {
return namesHead;
}
public void setName(List name) {
this.namesHead = name;
}
public String listModules() {
SessionFactory factory = HibernateLoginUtil.getFactory();
Session session = factory.openSession();
Query q1 = session.createQuery ("select id,name FROM TableUsrModuleGroup WHERE stat='active'");
for(Iterator it = q1.iterate() ; it.hasNext() ;) {
Object row[] = (Object[]) it.next();
namesHead.add (row[1]); //put the name
}
return SUCCESS;
}
in JSP page
<table>
<s:iterator status="status" value="namesHead" >
<tr><td><s:property/></td></tr>
</s:iterator>
</table>
(only name of group can i get from the above code, I need to display group name, group Id, and name of sub group and Id of sub group)
If you are using Hibernate, I think that the simplest option is to map the two classes and then recover both with a HQL query. For instance:
public class Group {
#OneToMany (mappedBy = "group", fetch = FetchType.LAZY)
private Collection <SubGroup> subgroup;
... // Rest of the class, getters and setters
}
public class SubGroup {
#ManyToOne (fetch = FetchType.LAZY)
private Group group;
... // Rest of the class, getters and setters
}
Then you have to make this HQL query to get the Group class:
Query q = session.createQuery ("FROM SubGroup");
List<SubGroup> subgroups = (List<SubGroup>) q.list();
Then you set an attribute with the subgroups in the Action and then you access to them in the jsp.
<table>
<s:iterator value="subgroups" >
<tr>
<td>
<s:property value="name"/>
</td>
<td>
<s:property value="id"/>
</td>
<td>
<s:property value="group.name"/>
</td>
<td>
<s:property value="group.id"/>
</td>
</tr>
</s:iterator>
</table>
I hope it helps =)
Fetch object, not specific fields from database. You must have getter and setters for that object in your action, then in JSP you can get all properties of that object (don't forget setters/getters for object).
Related
I am using treetable.js. as procedure i saved the child id and parent id. insert data is successfully inserted. but return data may show in table only or get the grouping error.
then i use the IGrouping Object get the Convertion error.
Please tell me the child parent loop structure for the below.
In Model:
public string name {get;set;}
public int childId {get;set;}
public int ParentId {get;set;}
In Controller:
var list = db.table.groupby(s=>s.parentId).toList();
return view(list);
In view:
<table id="example-basic">
<tr>
<th>Name</th>
<th>Data Id</th>
<th>Parent Id</th>
</tr>
#foreach (var item in Model)
{
<tr data-tt-id='#item.dataid' data-tt-parent-id='#item.dataparentid'>
<td>#item.Name</td>
<td>#item.dataid</td>
<td>#item.dataparentid</td>
</tr>
}
</table>
If you want just get rid of exception with grouping you should write like this:
var list = db.table.groupby(s => s.parentId).Select(x => new ChartOfAccount
{
ParentId = x.Key,
childId = x.First().childId,
name = x.First().name
}).toList();
return view(list);
As you can see you will get only one row for each ParentId becouse or grouping.
But i gess you searching for something else.
I am just trying to pass a List and display it dynamically in a table in the View. I have a Homepage Model and Homepage controller and the variables are being set right, but I can't figure out how to pass it to the view.
My model looks like this:
public class HomePageModel
{
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "ExtNum")]
public string ExtNum { get; set; }
[Display(Name = "PhoneDisplay")]
public List<PhoneDisplay> PhoneDisplay { get; set; }
}
and this is the controller:
public ActionResult Homepage(HomePageModel HpModel)
{
ViewBag.Welcome = "Welcome: ";
ViewBag.FirstName = HpModel.FirstName;
ViewBag.LastName = HpModel.LastName;
ViewBag.Extlbl = "Extension: ";
ViewBag.Ext = HpModel.ExtNum;
ViewBag.Todaylbl = "Today:";
ViewBag.Today = DateTime.Now;
DBOps ops = new DBOps();
HpModel.PhoneDisplay = ops.getDisplayInfo(HpModel.ExtNum);
return View(HpModel);
}
PhoneDisplay is a list that contains a line index, a description string and a 4 digit number. Each user will have at least 1 item in this list and maximum 6. I was able to pass the other parameters and display them in the view but I can't find a way to pass the list and display that dynamically.
EDIT
I made it this far but still can't find the list items.
#model AxlMVC.Models.HomePageModel
<table>
<caption style="font-weight:bold">Your Phone Information</caption>
<tr>
<th>Line Index</th>
<th>Display</th>
<th>Extension Number</th>
</tr>
#{
foreach (var item in Model.PhoneDisplay) //problems here
{
<tr>
<td>
#Html.Display(item.numplanindex)
</td>
<td>
#Html.Display(item.display)
</td>
<td>
#Html.Display(item.dnorpattern)
</td>
</tr>
}
}
</table>
EDIT
I debugged the cshtml file and the items in the foreach loop are being passed just fine too, but the table is not showing on the page and neither are the items all I can see is the caption and the headers for each column
Html.Display displays "data from the ViewData dictionary or from a model" as stated on MSDN. What it means is that it searches for the key in the ViewData dictionary with the value you pass in or a property in the Model with the specified name. E.g. Display("test") would search ViewData for the "test" key and the Model for the property named test. Since you are passing in property values that cannot work. Your options are:
Output the value directly, #item.numplanindex. This will output a string representation of the value.
Use Display, although this is not recommended. You could do Display("PhoneDisplay[1].numplanindex") to display numplanindex property of the second item in list.
Use DisplayFor, like DisplayFor(model => item.numplanindex). This is a strongly typed version of Display. It will either displays a string representation of the value or a template for the type, if you have one. You can also manage how the output is displayed via Data Annotations, e.g. DisplayFormatAttribute.
Use DisplayTextFor, like DisplayTextFor(model => item.numplanindex). This method outputs the string representation of the value.
Since you already have data annotations on the model, you could modify your view like this:
#model AxlMVC.Models.HomePageModel
<table>
<caption class="tableCaption">Your Phone Information</caption>
<tr>
<th>#Html.DisplayNameFor(model => model.PhoneDisplay[0].numplanindex)</th>
<th>#Html.DisplayNameFor(model => model.PhoneDisplay[0].display)</th>
<th>#Html.DisplayNameFor(model => model.PhoneDisplay[0].dnorpattern)</th>
</tr>
#{
foreach (var item in Model.PhoneDisplay)
{
<tr>
<td>#Html.DisplayTextFor(model => item.numplanindex)</td>
<td>#Html.DisplayTextFor(model => item.display)</td>
<td>#Html.DisplayTextFor(model => item.dnorpattern)</td>
</tr>
}
}
</table>
The line #Html.DisplayNameFor(model => model.PhoneDisplay[0].numplanindex) also works if PhoneDisplay contains no items. Only property metadata is collected, expression as such is not executed.
I am trying to understand why I get an exception when I try to get elements from a string array containing roles for my application.
error: Object reference not set to an instance of an object.
(ViewBag.roles)
Here is how I am getting the roles:
public ActionResult AdminRolesAndAccessRules()
{
String[] rolesArray;
rolesArray = Roles.GetAllRoles();
ViewBag.roles = rolesArray;
return PartialView();
}
and here is how I am using the information:
<div class="scroller">
<table>
#foreach (MembershipUserCollection muc in ViewBag.roles)
{
if(column == 1) {
classe = "whiteRow";
column = 0;
}
else {
classe = "grayRow";
column = 1;
}
<tr class="#classe">
<td class="adminSetFormRowUsuario">role</td>
<td class="adminSetFormRowGrupo"></td>
<td class="formAction centerAlign">
<img src="~/Images/editar.gif" alt="Editar"/>
<span style="margin-left:5px"></span>
<a href='javascript:AjaxRemoveUser("/Account/DeleteUser?role=#muc", "POST", "DinamicContent", "AdminSettingsTabsStructure")'><img src="~/Images/excluir.gif" alt="Excluir"/></a>
</td>
</tr>
}
</table>
Debugging I can see 2 values in ViewBag.roles but still the system complaining about a Null or not instantiated object.
// string array being assigned here
String[] rolesArray = Roles.GetAllRoles();
ViewBag.roles = rolesArray;
Debbugging I can see 2 values in ViewBag.rules but still the system
complaining about a Null or not instatiated object.
Those 2 values are presumably the roles you assigned.
// This looks wrong...you are treating each string in the array as MembershipUserCollection
#foreach (MembershipUserCollection muc in ViewBag.roles)
{
}
// instead, this should give you the role names
#foreach( string role in ViewBag.roles )
{
<div>#role</div>
}
I have the following model in MVC:
public class ParentModel
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public IEnumerable<ChildModel> Children { get; set; }
}
When I want to display all of the children for the parent model I can do:
#Html.DisplayFor(m => m.Children)
I can then create a ChildModel.cshtml display template and the DisplayFor will automatically iterate over the list.
What if I want to create a custom template for IEnumerable?
#model IEnumerable<ChildModel>
<table>
<tr>
<th>Property 1</th>
<th>Property 2</th>
</tr>
...
</table>
How can I create a Display Template that has a model type of IEnumerable<ChildModel> and then call #Html.DisplayFor(m => m.Children) without it complaining about the model type being wrong?
Like this:
#Html.DisplayFor(m => m.Children, "YourTemplateName")
or like this:
[UIHint("YourTemplateName")]
public IEnumerable<ChildModel> Children { get; set; }
where obviously you would have ~/Views/Shared/DisplayTemplates/YourTemplateName.cshtml:
#model IEnumerable<ChildModel>
<table>
<tr>
<th>Property 1</th>
<th>Property 2</th>
</tr>
...
</table>
This is in reply to Maslow's comment. This is my first ever contribution to SO, so I don't have enough reputation to comment - hence the reply as an answer.
You can set the 'TemplateHint' property in the ModelMetadataProvider. This would auto hookup any IEnumerable to a template you specify. I just tried it in my project. Code below -
protected override CachedDataAnnotationsModelMetadata CreateMetadataFromPrototype(CachedDataAnnotationsModelMetadata prototype, Func<object> modelAccessor)
{
var metaData = base.CreateMetadataFromPrototype(prototype, modelAccessor);
var type = metaData.ModelType;
if (type.IsEnum)
{
metaData.TemplateHint = "Enum";
}
else if (type.IsAssignableFrom(typeof(IEnumerable<object>)))
{
metaData.TemplateHint = "Collection";
}
return metaData;
}
You basically override the 'CreateMetadataFromPrototype' method of the 'CachedDataAnnotationsModelMetadataProvider' and register your derived type as the preferred ModelMetadataProvider.
In your template, you cannot directly access the ModelMetadata of the elements in your collection. I used the following code to access the ModelMetadata for the elements in my collection -
#model IEnumerable<object>
#{
var modelType = Model.GetType().GenericTypeArguments[0];
var modelMetaData = ModelMetadataProviders.Current.GetMetadataForType(null, modelType.UnderlyingSystemType);
var propertiesToShow = modelMetaData.Properties.Where(p => p.ShowForDisplay);
var propertiesOfModel = modelType.GetProperties();
var tableData = propertiesOfModel.Zip(propertiesToShow, (columnName, columnValue) => new { columnName.Name, columnValue.PropertyName });
}
In my view, I simply call #Html.DisplayForModel() and the template gets loaded. There is no need to specify 'UIHint' on models.
I hope this was of some value.
In my question about not getting output from views, I actually have an example of how to template a model with a collection of child models and have them all render.
ASP.NET Display Templates - No output
Essentially, you need to create a model that subclasses List<T> or Collection<T> and use this:
#model ChildModelCollection
#foreach (var child in Model)
{
Html.DisplayFor(m => child);
}
In your template for the collection model to iterate and render the children. Each child needs to strongly-typed, so you may want to create your own model types for the items, too, and have templates for those.
So for the OP question:
public class ChildModelCollection : Collection<ChildModel> { }
Will make a strongly-typed model that's a collection that can be resolved to a template like any other.
The actual "valid answer" is -IMHO- not correctly answering the question. I think the OP is searching for a way to have a list template that triggers without specifying the UIHint.
Magic stuff almost does the job
Some magic loads the correct view for a specified type.
Some more magic loads the same view for a collection of a specified type.
There should be some magic that iterates the same view for a collection of a specified type.
Change the actual behavior?
Open your favorite disassembler. The magic occurs in System.Web.Mvc.Html.TemplateHelpers.ExecuteTemplate. As you can see, there are no extensibility points to change the behavior. Maybe a pull request to MVC can help...
Go with the actual magic
I came up with something that works. Create a display template ~/Views/Shared/DisplayTemplates/MyModel.cshtml.
Declare the model as type object.
If the object is a collection, iterate and render the template again. If it's not a collection, then show the object.
#model object
#if (Model is IList<MyModel>)
{
var models = (IList<MyModel>)Model;
<ul>
#foreach (var item in models)
{
#Html.Partial("DisplayTemplates/MyModel", item)
}
</ul>
} else {
var item = (MyModel)Model;
<li>#item.Name</li>
}
}
Now DisplayFor works without UIHint.
We have a form and depending upon the circumstances we want to switch between an add operation and an update operation from the same form. Below is a cut down version of our form.
Effectively the "Order number" textbox is disabled and can never be edited in this form. Now, the scenario is a bit like this:
The first time the user lands on this form, the "Order number" text box is blank.
The user enters a customer name and submits the form.
At this point in the controller action, we get the max value of order number in the database and increment the order number by 1 . We then add that new record in the database.
If that operation is successful, we update the current form and the "Order Number" textbox should now be updated with the order number created in the previous step AND also what should happen is that we are now in Edit mode.
Say the user then updates the "Customer name" and submits the form, the record in the database should be updated in this instance.
Now for some code:
The View:
<%: Html.TextBox("OrderNumber", Model.OrderNumber == 0 ? "" : Model.OrderNumber.ToString(), new { #disabled = "true" })%>
The controller:
public ActionResult Index()
{
var customerOrderModel = new CustomerOrderModel();
return View(customerOrderModel);
}
public ActionResult Add(CustomerOrderModel customerOrderModel, FormCollection values)
{
// We write the logic for either the add or update.
return this.View("Index", customerOrderModel);
}
I have removed the code from the Add action because from putting breakpoints we know that the "// We write the logic for either the add or update." is not the problem.
Now where we are having trouble is this. We can add the new entry in the table following which the "Order Number" field gets updated and is displayed correctly. However, after we change the customer name and try to update, the customerOrderModel passed into the "Add" action shows that the order number being passed is 0(which is our default in the system and which is used to determine if we are performing an add or update operation).
So the question is why is our textbox getting updated, which would seem to indicate that our model is getting updated, but then when we try to submit, the correct model doesn't get passed in? Moreover, why is it that the Index action doesn't get hit after the "Add" action is completed? What do we have to do to get things to work the way we want them to?
Model
namespace Demo.Models
{
public class Order
{
public int OrderId { get; set; }
public string CustomerName { get; set; }
}
public class OrderDb:DbContext
{
public DbSet<Order> Orders { get; set; }
}
}
View
#model Demo.Models.Order
<form action="/" method="post">
<table>
<tr>
<td>#Html.LabelFor(m=>m.OrderId)</td>
<td>
#Html.EditorFor(m => m.OrderId)
</td>
</tr>
<tr>
<td>
#Html.LabelFor(m=>m.CustomerName)
</td>
<td>
#Html.EditorFor(m=>m.CustomerName)
</td>
</tr>
<tr>
<td></td>
<td>
<input type="submit" name="submit" value="submit" />
</td>
</tr>
</table>
</form>
Action
public ActionResult Index(Order o)
{
if (o.CustomerName != null)
{
using (OrderDb db = new OrderDb())
{
db.Entry(o).State = o.OrderId == 0 ? EntityState.Added : EntityState.Modified;
db.SaveChanges();
ModelState.Clear();
}
}
return View(o);
}
This is because HtmlHelpers look to ModelState for values first and then uses the values you explicitly use.
So when you add the entity you get ["Id"]=0 inside your model state.
So solve you have to clear your ModelState with .Clear() after a successful add.