Expand and Collapse asp.net TreeView using javascript

5 ביוני 2009

 


אנחנו מקימים כעת בסלע תת אתר חדש לרישום סטודנטים להסמכות.

 

באחד הדפים הפנימיים רצינו להשתמש ב – TreeView Control שקיים ב – Asp.net,

 

כשרצינו לבצע Collapse All ו – Expand All ל – tree, גילינו שיש לו פונקציות שיודעות לבצע את זה אבל זה בצד השרת, וזה לא נשמע לי הגיוני לללכת לשרת כדי לסגור או לפתוח את ה – tree,

 

ולכן בקשתי מאחי יוסי גולדברג לכתוב פונקציית java script שיודעת לפתוח ולסגור את ה – tree view,

 

הוא עשה עבודה מצויינת, וכתב קובץ JS שמכיל את הפונקציות הנדרשות, ואז חשבתי לעצמי למה שלא נירש מ – treeView ונוסיף את היכולת של להרחיב ולכווץ את ה – tree מ – java script,

 

אחרי שכתבתי את ה – control, יצרתי פרויקט ב – CodePlex בשם – AspNetControls (איך השם לא היה תפוס ?) את הפרויקט עצמו אפשר להוריד מכאן.

 

ואני אשמח לתת הרשאות לכל מי שרוצה להוסיף Controls לפרויקט. (אני מקווה שאני יוסיף לפרוייקט עוד controls)

 

 

הנה הקוד + הסברים (אחרי הקוד)

 

 



[assembly: WebResource(CollapseExpandTreeView.JS_URL, "text/javascript", PerformSubstitution = true)]


 


namespace Controls.CollapseExpandTreeView


{


    public class CollapseExpandTreeView : TreeView


    {


        #region Private Properties


        private HtmlInputButton Expand { get; set; }


        private HtmlInputButton Collapse { get; set; }


        #endregion


 


        #region Const


        private const string CSS_CLASS_EXPAND = "CssClassExpand";


        private const string CSS_CLASS_COLLAPSE = "CssClassCollapse";


        private const string EXPAND_TEXT = "ExpandText";


        private const string COLLAPSE_TEXT = "CollapseText";


        internal const string JS_URL = "Controls.CollapseExpandTreeView.ExpandCollapse.js";


        #endregion


 


        #region Ctor


        public CollapseExpandTreeView()


        {


            Expand = new HtmlInputButton();


            Collapse = new HtmlInputButton();


 


            ExpandText = "Expand All";


            CollapseText = "Collapse All";


        }


        #endregion


 


        #region Method


 


        /// <summary>


        /// Return string value from ViewState


        /// </summary>


        /// <param name="key">The key in The ViewState</param>


        /// <returns></returns>


        private string GetFromViewState(string key)


        {


            string s = (string)ViewState[key];


            return ((s == null) ? String.Empty : s);


        }


 


        /// <summary>


        /// Return string value of property that locate in the base type and it is not public


        /// </summary>


        /// <param name="propName">The property name</param>


        /// <returns></returns>


        private string GetValueFromReflaction(string propName)


        {


            Type type = GetType().BaseType;


            PropertyInfo pi = type.GetProperty(propName, BindingFlags.Instance | BindingFlags.NonPublic);


            object value = pi.GetValue(this, null);


            return value.ToString();


        }


 


        /// <summary>


        /// Gets the Expand Image Url


        /// </summary>


        private string ExpandImageUrlInternal


        {


            get


            {


                string url = GetValueFromReflaction("ExpandImageUrlInternal");


                if (url == "")


                {


                    // The default expand image url


                    url = "/WebResource.axd?d=wheI3Jge_pneveLkEraSoYxlmKNnqYa0X1_njXGO0bg1&t=633744831123074071";


                }


 


                return url;


            }


        }


 


        /// <summary>


        /// Gets the Collapse Image Url


        /// </summary>


        private string CollapseImageUrlInternal


        {


            get


            {


                string url = GetValueFromReflaction("CollapseImageUrlInternal");


                if (url == "")


                {


                    // The default collapse image url


                    url = "/WebResource.axd?d=wheI3Jge_pneveLkEraSoeJ2AkLjYF7aizzZ7NzLi441&t=633744831123074071";


                }


                return url;


            }


        }


 


        #endregion


 


        #region Public Properties


        [Category("Collapse Expand")]


        [Description("Css Class for the expand button")]


        public string CssClassExpand


        {


            get


            {


                return GetFromViewState(CSS_CLASS_EXPAND);


            }


            set


            {


                ViewState[CSS_CLASS_EXPAND] = value;


            }


        }


 


        [Category("Collapse Expand")]


        [Description("Css Class for the collapse button")]


        public string CssClassCollapse


        {


            get


            {


                return GetFromViewState(CSS_CLASS_COLLAPSE);


            }


            set


            {


                ViewState[CSS_CLASS_COLLAPSE] = value;


            }


        }


 


        [Category("Collapse Expand")]


        [Description("Text for the expand button")]


        [DefaultValue("Expand All")]


        public string ExpandText


        {


            get


            {


                return GetFromViewState(EXPAND_TEXT);


            }


            set


            {


                ViewState[EXPAND_TEXT] = value;


            }


        }


 


        [Category("Collapse Expand")]


        [Description("Text for the collapse button")]


        [DefaultValue("Collapse All")]


        public string CollapseText


        {


            get


            {


                return GetFromViewState(COLLAPSE_TEXT);


            }


            set


            {


                ViewState[COLLAPSE_TEXT] = value;


            }


        }


        #endregion


 


        #region Override


 


        protected override void Render(HtmlTextWriter writer)


        {


            // Add the data for the collapse button


            Collapse.Attributes["class"] = CssClassCollapse;


            Collapse.Value = CollapseText;


            // Register the onclick evenr to the ChnageTreeViewStatus function


            Collapse.Attributes["onclick"] = string.Format("ChnageTreeViewStatus('{0}', '{1}')", ClientID, CollapseImageUrlInternal);


 


            // Add the data for the expand button


            Expand.Attributes["class"] = CssClassExpand;


            Expand.Value = ExpandText;


            // Register the onclick evenr to the ChnageTreeViewStatus function


            Expand.Attributes["onclick"] = string.Format("ChnageTreeViewStatus('{0}', '{1}')", ClientID, ExpandImageUrlInternal);


 


            // Start rendering the tree


            // we render a table with two rows, in the first row we render two cells, in each cell we render one button,


            // and in other row we render a cell with the tree.


            writer.RenderBeginTag(HtmlTextWriterTag.Table);


            writer.RenderBeginTag(HtmlTextWriterTag.Tr);


            writer.RenderBeginTag(HtmlTextWriterTag.Td);


            Expand.RenderControl(writer);


            writer.RenderEndTag();  //HtmlTextWriterTag.Td


            writer.RenderBeginTag(HtmlTextWriterTag.Td);


            Collapse.RenderControl(writer);


            writer.RenderEndTag();  //HtmlTextWriterTag.Td


            writer.RenderEndTag();  //HtmlTextWriterTag.Tr


            writer.RenderBeginTag(HtmlTextWriterTag.Tr);


            writer.AddAttribute(HtmlTextWriterAttribute.Colspan, "2");


            writer.RenderBeginTag(HtmlTextWriterTag.Td);


            base.Render(writer);


            writer.RenderEndTag();  //HtmlTextWriterTag.Td


            writer.RenderEndTag();  //HtmlTextWriterTag.Tr


            writer.RenderEndTag();  //HtmlTextWriterTag.Table


        }


 


        protected override void OnPreRender(EventArgs e)


        {


            // Register the ExpandCollpase.js in the page


            Page.ClientScript.RegisterClientScriptResource(GetType(), JS_URL);


 


            base.OnPreRender(e);


        }


        #endregion


    }


}


 

 

הסברים:

 

בהתחלה אנחנו רושמים את קובץ ה – JS כ – WebResource של ה – assembly (הקובץ מסומן כ – Embedded Resource)

 

אנחנו מחזיקים שני HtmlInputButton וב – Ctor אנחנו מייצרים אותם, ונותנים למאפיינים את הערך ברירת מחדל.

 

שני המאפיינים –  ExpandImageUrlInternal ו – CollapseImageUrlInternal מחזירים את ה – ImageUrl שלהם על ידי Reflection, אנחנו צריכים אותם היות וה – TreeView ב – JS יש לו מתודה של – Toggle, והוא אינו מחזיק את המצב של ה – Node, ולכן כדי לדעת האם צריך להחליף את המצב, אני צריך לשלוח את ה – Url של התמונה כדי לבדוק מול זה האם צריך להפעיל את ה – Toggle.

 

לאחריו יש מספר מאפיינים עבור הלחצנים, (Css  ו – Text)

 

במתודת ה – PreRender אנחנו רושמים לדף את קובץ ה – JS

 

ובמתודת ה – Render אנחנו מייצרים טבלה שבשורה הראשונה אנחנו מיצרים שני עמודות ובכל עמודה אחד מהלחצנים, ובשורה השנייה את ה – Tree.

השורה החשובה ב – Render היא הרישום ל – onclick של הלחצנים.

 

 



Collapse.Attributes["onclick"] = string.Format("ChnageTreeViewStatus('{0}', '{1}')", ClientID, CollapseImageUrlInternal)


 

כעת נראה את קובץ ה – JS

 

 



// Collapse or Expand all nodes/


// param: treeId – The id of the treeView to perform the operation


// param: imgUrl – The Collapse or Expand image url, if send the Collapse image, then all nodes will collapse


function ChnageTreeViewStatus(treeId, imgUrl) {


 


    // Get all nodes ids that have children


    var parentIds = GetAllParentIds(treeId);


 


    for (var i = 0; i < parentIds.length; i++) {


 


        // Get the iamge of each node


        var parentImg = GetParentImg(treeId, parentIds[i]);


 


        // If the mode image is the same like imgUrl, we need to toggle


        if (parentImg.src.indexOf(imgUrl) > -1) {


 


            // Get the node object


            var parent = GetParentObject(treeId, parentIds[i]);


            // Get the child node object (to send as parameter for ToggleNode function)


            var childe = document.getElementById(GetChildeId(treeId, parentIds[i]));


            // Get the TreeView javascript object


            var obj = eval(treeId + "_Data");


 


            // Perform the ToggleNode function


            TreeView_ToggleNode(obj, treeId[i], parent, ' ', childe);


        }


    }


}


 


function GetParentImg(treeId, nodeId) {


    var node = GetParentObject(treeId, nodeId);


    var imgNode = node.getElementsByTagName('img');


 


    return imgNode.length > 0 ? imgNode[0] : null;


}


 


function GetParentObject(treeId, nodeId) {


    var id = treeId + 'n' + nodeId;


    return document.getElementById(id);


}


 


function GetChildeId(treeId, NodeId) {


    return treeId + 'n' + NodeId + 'Nodes';


}


 


function GetAllParentIds(treeId) {


    var aElements = document.getElementById(treeId).getElementsByTagName('a');


    var parentIds = new Array();


    var j = 0;


 


    for (var i = 0; i < aElements.length; i++) {


        if (aElements[i].id.indexOf('Nodes') < 0 && aElements[i].id.indexOf(treeId + 'n') > -1) {


            parentIds[j] = aElements[i].id.substr(treeId.length + 1);


            j++;


        }


    }


    return parentIds;


}


 

הפונקציה הראשית ChangeTreeViewStatus מקבלת את ה – Id של ה – tree view ואת התמונה שלפיה אנחנו יודעים מה לעשות.

 

אנחנו מקבלים את כל ה – nodes שיש להם ילדים.

 

בודקים האם התמונה שלהם היא אותו תמונה שקבלנו.

 

נמצא את האובייקט ונפעיל עליו את המתודה Toggle_Node.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

5 תגובות

  1. Rotem Bloom7 ביוני 2009 ב 16:56

    נראה מאוד נחמד וגם שימושי רק יש טעות כתיב ב:
    ChnageTreeViewStatus
    ה-change כתוב לא נכון chnage

    אבל שטויות 🙂

    הגב
  2. Shlomo7 ביוני 2009 ב 21:16

    תודה אני אתקן

    הגב
  3. יבגני11 בנובמבר 2010 ב 8:14

    אחלה פוסט

    הגב
  4. אלדר22 בנובמבר 2011 ב 23:53

    שאלות לא כל-כך קשורות:
    1. האם TreeView מתאים גם לעץ אפשרויות שאינם דפים שונים באתר אלא בקשות שונים לנתונים שמתקבלות כולן בדף אחד? אם-כן איך עושים זאת? אם-לא איזה פקד כן מתאים לכך?
    2.

    הגב
  5. Shlomo23 בנובמבר 2011 ב 7:54

    לא כל כך הבנתי את השאלה – אתה מוזמן לפנות אלי דרך דף צור קשר

    הגב