locked
Accordion for Dynamic Data Entities RRS feed

  • Question

  • User-635256440 posted

    Hello everyone,

    I'm trying to implement an Accordion style for a "Dynamic Data" application and can't find much help.  Has anyone been able to do this whether through jQuery or Ajax?  Would appreciate your help.

    The reason for Accordion is that I have over 150 fields and the form looks overwhelming without an Accordion or Tab to simplify.  So, if you have other ideas would love to hear from ya.

    Thanks.

    Thursday, April 26, 2012 4:19 PM

Answers

All replies

  • User-330204900 posted

    Hi Bja58, I used an AJAX tab control in an Entity Template see this articel for tha basic idea Custom Entity Templates – Dynamic Data 4 I basically used the AJAX Control Toolkit Tab control in an Entity Template to achive this. I should really do an article for that.

    Friday, April 27, 2012 7:24 AM
  • User-635256440 posted

    Thanks Steve.  I had actually read your article before...nice work.  I'd love to see a working sample of an Accordion using AJAX.

    Can anyone else help?

    Monday, April 30, 2012 7:03 PM
  • User1865095734 posted

    Hi,

         If you go for jquery stuff. you can use jquery UI accordion. That is a nice stuff. search for "Jquery UI accordion"

    Thanks

    Raj

    Thursday, May 3, 2012 6:35 AM
  • User350138131 posted

    The reason for Accordion is that I have over 150 fields and the form looks overwhelming without an Accordion or Tab to simplify.

    To apply the accordion for this purpose is hardly possible.
    You can create your own pseudo-accordion, providing it with the appropriate functionality.
    The task of mapping groups of fields, I decided to use an ordinary Combo Box. This solution I found the easiest.
    If this interest you, I can put the code.

    Friday, May 11, 2012 1:28 AM
  • User-330204900 posted

    Try the JuiceUI that will give you the jQuery UI accordian and it should be easyer to do I will give it a try in the morning,

    Friday, May 11, 2012 7:08 PM
  • User350138131 posted

    Hi, Sjnaughton. If you can use jQuery Accordion for Dynamic Data Entities, I considered it a miracle, and once again I'll be grateful! In the meantime, I will present a pseudo-accordion, I was talking about. This example is based on your http://csharpbits.notaclue.net/2010/02/grouping-field-on-details-edit-and.html. Here it is.

    [AttributeUsage(AttributeTargets.Class)]
    public class ColumnsGroupsAttribute : Attribute
    {
    	public string[] Groups { get; set; }
    }
    
    public static string[] GetColumnsGroups(this MetaTable table)
    {
    	var groups = table.Attributes.OfType<ColumnsGroupsAttribute>().DefaultIfEmpty(new ColumnsGroupsAttribute()).First() as ColumnsGroupsAttribute;
    	return groups.Groups;
    }
    
    public static int GetGroupIndex(this MetaColumn column)
    {
    	if (column.GetAttributeOrDefault<DisplayAttribute>().GroupName == null)
    		return -1;
    	else
    		return Convert.ToInt16(column.GetAttributeOrDefault<DisplayAttribute>().GroupName);
    }
     public partial class DefaultEntityTemplate : System.Web.DynamicData.EntityTemplateUserControl
        {
            public MetaColumn currentColumn;
            public String groupName;
            public Boolean groupHeading;
    
            string[] clgr = null;
            private int currentGroup = -1;
    
            protected override void OnLoad(EventArgs e)
            {
                // get a list of groups ordered by group name
                var groupings = from t in Table.GetScaffoldColumns(Mode, ContainerType)
    							group t by t.GetGroupIndex() into menu
                                orderby menu.Key
                                select menu.Key;
    
    			clgr = Table.GetColumnsGroups();
                // loop through the groups
                foreach (var groupId in groupings)
                {
                    // get columns for this group
                    var columns = from c in Table.GetScaffoldColumns(Mode, ContainerType)
    							  where (groupId == -1 && c.GetAttributeOrDefault<DisplayAttribute>().GroupName == null) || c.GetAttributeOrDefault<DisplayAttribute>().GroupName == groupId.ToString()
                                  orderby c.GetAttributeOrDefault<DisplayAttribute>().GetOrder()
                                  select c;
    
                    // add group separator
                    if (groupId!=-1)
                    {
                        groupHeading = true;
                        currentColumn = columns.First();
    					currentGroup = groupId;
                        groupName = groupId.ToString();
                        Control item = new _NamingContainer();
                        EntityTemplate1.ItemTemplate.InstantiateIn(item);
                        EntityTemplate1.Controls.Add(item);
                    }
    
                    // add fields
                    foreach (MetaColumn column in columns)
                    {
                        groupHeading = false;
                        currentColumn = column;
                        Control item = new _NamingContainer();
                        EntityTemplate1.ItemTemplate.InstantiateIn(item);
                        EntityTemplate1.Controls.Add(item);
                    }
                }
            }
    
            protected void Label_Init(object sender, EventArgs e)
            {
                if (!groupHeading)
                {
                    Label label = (Label)sender;
                    label.Text = currentColumn.DisplayName;
    				int gr = currentColumn.GetGroupIndex();
    				label.GetParentControl<HtmlTableRow>().Attributes["class"] += " gr gr" + gr.ToString();
                }
                else
                {
                    Label label = (Label)sender;
    				label.CssClass = "button";
    				label.Width = Unit.Percentage(100);
                    label.Text = clgr[Convert.ToInt16(groupName)];
                    var parentCell = label.GetParentControl<HtmlTableCell>();
                    parentCell.ColSpan = 2;
    				label.Attributes["onclick"] = "return ChangeTab(event);";
    				label.Attributes["title"] = currentGroup.ToString();
                    //parentCell.Attributes.Add("class", "DDGroupHeader");
                }
            }
    
            protected void DynamicControl_Init(object sender, EventArgs e)
            {
                DynamicControl dynamicControl = (DynamicControl)sender;
                dynamicControl.DataField = currentColumn.Name;
                if (groupHeading)
                {
                    // hide Dynamic Control maybe overkill
                    dynamicControl.Visible = false;
                    // get the parent cell
                    var parentCell = dynamicControl.GetParentControl<HtmlTableCell>();
                    // hide the cell
                    parentCell.Visible = false;
                }
            }
    
            public class _NamingContainer : Control, INamingContainer { }
        }

    dd.js

    function pageLoad() {
    	$(".button").button();
    	ChangeTab(null);
    }
    
    function ChangeTab(evt, bSave) {
    	var o;
    	if (evt != null) {
    		evt = evt || window.event;
    		o = evt.target || evt.srcElement;
    		if (o != null) {
    			o = o.parentNode;
    		}
    	}
    	else {
    		o = $(".button")[0]
    	}
    	if (o == null)
    		return;
    	var groupNum = o.title
    	var oD = $(".gr")
    	if (groupNum == null)
    		oD.show();
    	else {
    		oD.hide();
    		oD = $(".gr-1")
    		oD.show();
    		if (groupNum != "-1") {
    			oD = $(".gr" + groupNum)
    			oD.show(100); 
    		}
    	}
    }

     

        [MetadataType(typeof(OrderMetadata))]
        public partial class Order
        {
    		[ColumnsGroups(Groups = new string[] { "Dates", "Ship Info", "Other Info" })]
            internal partial class OrderMetadata
            {
                public Object OrderID { get; set; }
                public Object CustomerID { get; set; }
                public Object EmployeeID { get; set; }
                [Display(Order = 0,GroupName = "0")]
                public Object OrderDate { get; set; }
                [Display(Order = 1,GroupName = "0")]
                public Object RequiredDate { get; set; }
                [Display(Order = 2,GroupName = "0")]
                public Object ShippedDate { get; set; }
    
                [Display(Order = 4,GroupName = "1")]
                public Object ShipVia { get; set; }
                [Display(Order = 5,GroupName = "1")]
                public Object Freight { get; set; }
                [Display(Order = 3,GroupName = "1")]
                public Object ShipName { get; set; }
                [Display(Order = 6,GroupName = "1")]
                public Object ShipAddress { get; set; }
                [Display(Order = 7,GroupName = "1")]
                public Object ShipCity { get; set; }
                [Display(Order = 8,GroupName = "1")]
                public Object ShipRegion { get; set; }
                [Display(Order = 9,GroupName = "1")]
                public Object ShipPostalCode { get; set; }
                [Display(Order = 10,GroupName = "1")]
                public Object ShipCountry { get; set; }
                // Entity Ref 
                [Display(Order = 12)]
                public Object Customer { get; set; }
                // Entity Ref 
                [Display(Order = 13)]
                public Object Employee { get; set; }
                // Entity Set 
                [Display(Order = 14)]
                public Object Order_Details { get; set; }
                // Entity Ref 
                [Display(Order = 11,GroupName = "1")]
                public Object Shipper { get; set; }
            }
        }

    Site.master

    <link href="css/ui-lightness/jquery-ui-1.8.13.custom.css" rel="stylesheet" type="text/css" />
    
    <asp:ScriptManager ID="ScriptManager1" runat="server">
    	<Scripts>
    		<asp:ScriptReference Path="Scripts/jquery-1.5.2.min.js" />
    		<asp:ScriptReference Path="Scripts/jquery-ui-1.8.17.custom.min.js" />
    		<asp:ScriptReference Path="Scripts/DD.js" />
    	</Scripts>
    </asp:ScriptManager>

    Thank you.






     

    Sunday, May 13, 2012 2:10 AM
  • User-330204900 posted

    Hi Valz, here is my AJAX tab Entity templte

    public partial class AjaxTabGroupsTemplate : System.Web.DynamicData.EntityTemplateUserControl
    {
        private const string STR__AjaxActiveTabIndex = "_AjaxActiveTabIndex";
        private String _seperator;
        private TabContainer _tabContainer;
    
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            _seperator = this.ClientIDSeparator.ToString();
    
            // create a row with one cell to fill the
            // surrounding table from the form view
            var row = new HtmlTableRow();
            var td = new HtmlTableCell();
            row.Controls.Add(td);
            this.Controls.Add(row);
    
            // create tab container to hold each children column
            _tabContainer = new TabContainer()
                {
                    ID = "tabContainer_" + Table.Name,
                    // set auto post back to enable events
                    AutoPostBack = true
                };
    
            _tabContainer.ActiveTabChanged += tabContainer_ActiveTabChanged;
    
            // add the tab container to the page
            td.Controls.Add(_tabContainer);
        }
    
        private void tabContainer_ActiveTabChanged(object sender, EventArgs e)
        {
            Page.AddValueToSession<int>(Table.Name + STR__AjaxActiveTabIndex, _tabContainer.ActiveTabIndex);
        }
    
        protected override void OnLoad(EventArgs e)
        {
            var activeTab = Page.GetValueFromSession<int>(Table.Name + STR__AjaxActiveTabIndex);
            _tabContainer.ActiveTabIndex = activeTab;
    
    
            // get a list of groups ordered by group name
            var scaffoldedColumns = Table.GetScaffoldColumns(Mode, ContainerType);
            //var groupings = from t in scaffoldedColumns
            //                group t by t.GetAttributeOrDefault<GroupAttribute>().Index into columnGroups
            //                orderby columnGroups.Key
            //                select columnGroups.Key;
    
            var groupAttribute = Table.GetAttribute<GroupNamesAttribute>();
            if (groupAttribute == null)
                throw new InvalidOperationException("A GroupsAttribute is required for AJAX tab group to work.");
    
            //if (groupings.Count() != groupAttribute.Groups.Count)
            //    throw new InvalidOperationException("");
    
            // add table for each group
            //foreach (var gi in groupings)
            foreach (var gi in groupAttribute.Groups)
            {
                var groupName = gi.Value;//groupAttribute.Groups[gi];
                // create table panel
                var tabPanel = new TabPanel()
                    {
                        ID = (Table.Name + _seperator + groupName).Replace(" ", _seperator),
                        HeaderText = groupName
                    };
    
                // add tab to tab container
                _tabContainer.Tabs.Add(tabPanel);
    
                // create table to go inside tab
                var tabTable = new HtmlTable();
                tabTable.Attributes.Add("class", "DDDetailsTable");
                tabTable.Attributes.Add("cellpadding", "6");
                tabTable.Attributes.Add("Name", groupName);
    
                // add the DynamicControl to the tab panel
                tabPanel.Controls.Add(tabTable);
    
                // get columns for this group
                var columns = from c in Table.GetScaffoldColumns(Mode, ContainerType)
                              where c.GetAttributeOrDefault<GroupAttribute>().Index == gi.Key
                              orderby c.GetAttributeOrDefault<GroupAttribute>().Index
                              select c;
    
                // add fields
                foreach (MetaColumn column in columns)
                {
                    var tableRow = new HtmlTableRow();
                    tabTable.Controls.Add(tableRow);
    
                    var tdHeader = new HtmlTableCell();
                    tdHeader.Attributes.Add("class", "DDLightHeader");
                    tdHeader.InnerText = column.DisplayName;
    
                    // add header cell to row
                    tableRow.Controls.Add(tdHeader);
    
                    var tdData = new HtmlTableCell();
                    var dynamicControl = new DynamicControl(Mode);
                    dynamicControl.DataField = column.Name;
                    dynamicControl.ValidationGroup = this.ValidationGroup;
                    tdData.Controls.Add(dynamicControl);
    
                    // add data cell to row
                    tableRow.Controls.Add(tdData);
                }
            }
        }
    
        protected void Label_PreRender(object sender, EventArgs e)
        {
            Label label = (Label)sender;
            DynamicControl dynamicControl = (DynamicControl)label.FindControl("DynamicControl");
            FieldTemplateUserControl ftuc = dynamicControl.FieldTemplate as FieldTemplateUserControl;
    
            if (ftuc != null && ftuc.DataControl != null)
                label.AssociatedControlID = ftuc.DataControl.GetUniqueIDRelativeTo(label);
        }
    
        public class _NamingContainer : Control, INamingContainer { }

    Which is what I will base the Accordian on obviousely I could use the Accordian fromt eh AJAX control toolkit but I facy trying the JuiceUI accordian as it uses jQuery UI :)

    You also need this:

    public class AdvancedEntityTemplateFactory : System.Web.DynamicData.EntityTemplateFactory
    {
        public override string BuildEntityTemplateVirtualPath(string templateName, DataBoundControlMode mode)
        {
            string path = base.BuildEntityTemplateVirtualPath(templateName, mode);
    
            if (File.Exists(HttpContext.Current.Server.MapPath(path)))
                return path;
    
            return path.Replace("_" + mode.ToString(), "");
        }
    
        public override EntityTemplateUserControl CreateEntityTemplate(MetaTable table, DataBoundControlMode mode, string uiHint)
        {
            var et = table.GetAttribute<EntityUIHintAttribute>();
            if (et != null && !String.IsNullOrEmpty(et.UIHint))
                return base.CreateEntityTemplate(table, mode, et.UIHint);
    
            return base.CreateEntityTemplate(table, mode, uiHint);
        }
    
        public override string GetEntityTemplateVirtualPath(MetaTable table, DataBoundControlMode mode, string uiHint)
        {
            var et = table.GetAttribute<EntityUIHintAttribute>();
            if (et != null && !String.IsNullOrEmpty(et.UIHint))
                return base.GetEntityTemplateVirtualPath(table, mode, et.UIHint);
    
            return base.GetEntityTemplateVirtualPath(table, mode, uiHint);
        }
    }

    Which is used like this:

    // add new entity template factory that works with single files also
    DefaultModel.EntityTemplateFactory = new AdvancedEntityTemplateFactory();
    

    in the Global.asax.cs to add advanced features to entity templates the main feature is that you only need one EntityTemplate (Default) for all the states (i.e. ReadOnly, Edit and Insert) which my AjaxTabControl takes advantage of.

    Sunday, May 13, 2012 4:10 AM
  • User350138131 posted

    Hi, Sjnaughton. Thank you, I'm starting to learn your decision

    Sunday, May 13, 2012 4:35 AM
  • User-330204900 posted

    As soon as I get a momnet I will get the accordian working too.

    Sunday, May 13, 2012 8:11 AM
  • User-330204900 posted

    Just added new Wijmo Tabs and Accordion sample to my blog here Creating a Tabbed Entity Template using Wijmo Open for Juice UI code download at bottom of the article.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, May 26, 2012 9:47 AM
  • User350138131 posted

    Hi, Steve.
    Sorry for the long silence. I was not feeling well.
    Thank you. This is an excellent and edifying work. Based on your example I built Tabbed Entity Template, which can be used by Default? ie if there is no GroupNamesAttribute, and in the absence GroupAttribute. I also added a radio button which allows you to choose between the Tabs and Accordion in real time. The only problem, juice.js not want to work with EnablePartialRendering = "false". Therefore, instead of using the Juice, I wrote a couple of lines on javascript and everything got better. (Neither the head nor the headache)
    Thanks again, Steve.

    P.S.
    bja58 probably forgot about this Thread

    Monday, September 10, 2012 5:02 AM