.NET Custom composite server control pass property to embedded javascript

Hello

I need held with creating custom control. I have created Custom control with a textbox and button. Control has a few properties like ServicePath, ServiceMethod to hold a string variable for calling a webservice. This is done through WebServiceProxy.invoke, but there is a problem. I need to pass these do embedded javascript.

.aspx

namespace WebControls
{
    [DefaultProperty("Text")]    
    [ToolboxData("<{0}:Text2Label runat=server></{0}:Text2Label>")]
    public class Text2Label : CompositeControl, INamingContainer
    {
        protected TextBox txtName = new TextBox();
        protected Label lblPopis = new Label();
        protected ImageButton ibOK = new ImageButton();        
        private string _servicePath;
        private string _serviceMethod;


        public override ControlCollection Controls
        {
            get
            {
                EnsureChildControls();
                return base.Controls;
            }
        }
        protected override void OnInit(EventArgs e)
        {
            EnsureChildControls();
            lblPopis.Text = "<b>" + _controlPopis + ":  </b>";
            ibOK.ImageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "WebControls.Images.accept.png");
            base.OnInit(e);
        }
        protected override void CreateChildControls()
        {
            Controls.Clear();
            InitializeDefaultSettings();

            txtName.Attributes.Add("style", "visibility:hidden;");
            ibOK.Attributes.Add("style", "visibility:hidden;");
            // Create user interface by using Controls collection
           
            Controls.Add(new LiteralControl("<table>"));
            Controls.Add(new LiteralControl("<tr>"));
            Controls.Add(new LiteralControl("<td>"));
            Controls.Add(lblPopis);
            Controls.Add(new LiteralControl("</td>"));
            Controls.Add(new LiteralControl("<td>"));
            Controls.Add(txtName);
            Controls.Add(new LiteralControl("</td>"));
            Controls.Add(new LiteralControl("<td>"));
            Controls.Add(ibOK);
            Controls.Add(new LiteralControl("</td>"));
            Controls.Add(new LiteralControl("</tr>"));
            Controls.Add(new LiteralControl("</table>"));
        }
        private void InitializeDefaultSettings()
        {
            ibOK.Attributes.Add("id", "ibOK");
            ibOK.Height = Unit.Pixel(26);
            ibOK.AlternateText = "Potvrdit zmenu";
            ibOK.Attributes.Add("OnClick", "return onOKClick();");

            txtName.Attributes.Add("id", "txtName");
            txtName.BorderColor = Color.Blue;
            txtName.BorderStyle = BorderStyle.Inset;
            txtName.BorderWidth = Unit.Pixel(1);
            txtName.Width = Unit.Pixel(0);
            txtName.Height = Unit.Pixel(0);
           
        }
        #region Properties
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string ServiceMethod
        {
            get
            {
                return _serviceMethod;
            }

            set
            {
                _serviceMethod = value;
            }
        }
        #endregion
        protected override void OnPreRender(System.EventArgs e)
        {
            base.OnPreRender(e);

            //Register script library.
            ScriptManagerHelper.RegisterClientScriptResource(
              this,
              typeof(Text2Label),
              "WebControls.ControlEvents.js");
 
        }  
    }
}

.js file

function onOKClick() {

    //Here i need to get values from property of a custom control

    Sys.Net.WebServiceProxy.invoke(servicepath, servicemethod, false);

    return false;

}


The js file is working OK and also the webserviceproxy with hand-typed default values. Am i missing something??? Do I need to create Ajax extender control for the textbox or button to get property values??

I figured out 1 way to get these properties to javascript file through this code:

aspx file:

this.Attributes.Add("serviceMethod",_serviceMethod);

js file:

    var r = document.getElementById(''); //here i need to get a controls ID
    alert(r.getAttribute('serviceMethod');

So there is another problem with getting a controls ID via javascript to access these attributes.

Do you know another approach???

thx
LVL 4
KendzastAsked:
Who is Participating?
 
Alexandre SimõesConnect With a Mentor Manager / Technology SpecialistCommented:
Ok mate, I'm sorry for this whole mess :)

1st thing: why did you decide to run through the complex process of creating a ServerControl instead of creating a Web User Control?
This would have been much easier and the problem you are having now would have never existed.

Anyway, your problem is caused by the fact that you have multiple Text2Label objects connecting to the same Javascript code and this code doesn't know which control called the OnEdit, OnCancel or OnOK click.
For this to work you need to pass the caller control ID into the methods.

For example:
ibEdit.Attributes.Add("OnClick", "return onEditClick(" + this.ClientID + ");");

now on the javascript you can reference exactly the caller object inner controls.

I think now we're in sync hun? :)
0
 
Alexandre SimõesManager / Technology SpecialistCommented:
Hi mate,

to get server-side property values within javascript you must use the <% %> tags.

For example, where you say:
var r = document.getElementById(''); //here i need to get a controls ID

you can write something like:
var r = document.getElementById('<%= txtUserName.ClientID %>');

this technique will also work for server-side properties you may have on the control.

Cheers!
0
 
KendzastAuthor Commented:
Hi

Thanks, but I know that... When u know the controls name which I am not.

I have this in control:

this.Attribute,Add("serviceMethod",_serviceMethod);

"this" is referencing the control itself for example in aspx page, where am I using my control:

<cc1:Text2Label ID="Text2Label1" runat="server" ServicePath="WebService1.asmx" ServiceMethod="HelloWorld" />

I need to get the ID "Text2Label1" to get his properties.

Do u know how to accomplish this?? Or do u know how to get ServiceMethod property in embedded javascript???

Thanks
0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
Alexandre SimõesManager / Technology SpecialistCommented:
The easiest way is to expose that inner control name on your parent control.
For example, if you add the following property to the parent control:

public string Text2Label1ClientID {get{ return this.Text2Label.ClientID;}}

if you need to access any control inside Text2Label control you can also expose it as a public string property.

This is not pretty and is far from being easy to maintain but is the only way I know to be able to expose inner controls to javascript usage since by design inner controls are declared as protected and being server-side controls you never know their Client-Side ID.


To simplify my advice goes in 2 direction... either:
1. If possible, don't break the main control into several smaller controls... build it all on the same control and then you can access everything from client-side.
2. Rethink your logic... I didn't get into much detail about what you're doing but from my experience, when implementations get nasty usually is because we're not thinking about it right.
0
 
KendzastAuthor Commented:
Thanks for response.

I think I didnt make clear what I am trying to accoplish. I try to explain.
I am building a custom server control for my web page. The main purpuse of this control is to make user friendly interpretation of data stored in SQL server.

I have a table with personal info (first name, last name, address etc.) I want to edit each info separately and store his new value to SQL server immediately. So the control has a Textbox, a Label and 3 buttons (Edit, Store and Cancel).
I dont want to do a postback every time I hit a button so I write the buttons behavior into a javascript and embedded it into my control.
The easiest way to store data from TextBox to SQL is through web service and webserviceproxy, but I need to pass property value serviceMethod and servicePath to embedded javascript. Reading a Textbox value is not a problem because I know his ID also I know the ID of other control (label and buttons) but I dont know the ID of the created control because it hasnt have one until I use it in aspx page.

How can I pass these properties to embedded javascript? Or do I need to create an Ajax control (namespace, prototype, register etc.)??? Or is there another way to accoplish my goals?? Could u please add here an javascript example???

I have tried ur solution before but I dont know how to access it from javascript. If I knew how to do it I could access the property ServiceMethod instead of trying to get main controls ID.

I could add these properties to the Texbox as his attributes and access it from javascript because I knew his ID, but I dont think that this is the clean solution.

I dont believe that I am the only one who is trying to accoplish something like this.

Thanks in advice
0
 
Alexandre SimõesManager / Technology SpecialistCommented:
"I dont want to do a postback every time I hit a button..."
Why don't you use an UpdatePanel?
You wouldn't have the undesired "flickr" and the implementation would always be server-side, making it plain easy.

Beside that, I didn't understand why do you have to create the control at runtime... why can't you create it at design-time and have it populated then?
0
 
KendzastAuthor Commented:
Hi

I think that we are not understanding each other. I am not trying to create control at runtime, but it is at design time.
Correct me if I am wrong please, but when I use an UpdatePanel the page runs through its whole Life Cycle beside of a javascript, right?
Some of my customers have very poor connection and making a Postback every time is not an option for me. One simple postback can last for 1-3 seconds. If I have 15 - 20 controls in my page its about 45 sec to click each button one time.

So I decided to post here my solution. The code is rough but I think u will get the idea.

 
Thanks
web controls cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using AjaxControlToolkit;

namespace WebControls
{
    [DefaultProperty("Text")]    
    [ToolboxData("<{0}:Text2Label runat=server></{0}:Text2Label>")]    
    public class Text2Label : CompositeControl, INamingContainer
    {
        protected TextBox txtName = new TextBox();
        protected Label lblMessage = new Label();
        protected Label lblPopis = new Label();
        protected Label lblSucFailText = new Label();
        protected ImageButton ibEdit = new ImageButton();
        protected ImageButton ibCancel = new ImageButton();
        protected ImageButton ibOK = new ImageButton();
        private string _controlPopis;
        private string _controlText;
        private string _servicePath;
        private string _serviceMethod;
        private Unit _controlWidth;
        private Unit _controlHeight;        

        public override ControlCollection Controls
        {
            get
            {
                EnsureChildControls();
                return base.Controls;
            }
        }
        protected override void OnInit(EventArgs e)
        {
            EnsureChildControls();
            lblPopis.Text = "<b>" + _controlPopis + ":  </b>";
            lblMessage.Text = _controlText;
            lblMessage.Width = _controlWidth;
            lblMessage.Height = _controlHeight;
            //string id = this.ID;// = "Txt2Lbl";            
            this.Attributes.Add("controlText", _controlText);
            this.Attributes.Add("controlWidth", _controlWidth.Value.ToString());
            this.Attributes.Add("controlHeight", _controlHeight.Value.ToString());
            this.Attributes.Add("servicePath", _servicePath);
            this.Attributes.Add("serviceMethod", _serviceMethod);
            ibCancel.ImageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "WebControls.Images.delete.png");
            ibEdit.ImageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "WebControls.Images.Edit.png");
            ibOK.ImageUrl = Page.ClientScript.GetWebResourceUrl(this.GetType(), "WebControls.Images.accept.png");
            base.OnInit(e);
        }
        protected override void CreateChildControls()
        {
            Controls.Clear();
            //inicializacia default nastaveni
            InitializeDefaultSettings();

            txtName.Attributes.Add("style", "visibility:hidden;");
            ibOK.Attributes.Add("style", "visibility:hidden;");
            ibCancel.Attributes.Add("style", "visibility:hidden;");                     

            // Create user interface by using Controls collection            
            Controls.Add(new LiteralControl("<table>"));
            Controls.Add(new LiteralControl("<tr>"));
            Controls.Add(new LiteralControl("<td>"));
            Controls.Add(lblPopis);
            Controls.Add(new LiteralControl("</td>"));
            Controls.Add(new LiteralControl("<td>"));
            Controls.Add(txtName);
            Controls.Add(lblMessage);
            Controls.Add(new LiteralControl("</td>"));
            Controls.Add(new LiteralControl("<td>"));
            Controls.Add(ibEdit);
            Controls.Add(ibOK);
            Controls.Add(ibCancel);
            Controls.Add(new LiteralControl("</td>"));
            Controls.Add(new LiteralControl("</tr>"));
            Controls.Add(new LiteralControl("<tr>"));
            Controls.Add(new LiteralControl("<td colspan=3>"));
            Controls.Add(lblSucFailText);
            Controls.Add(new LiteralControl("</td>"));
            Controls.Add(new LiteralControl("</tr>"));
            Controls.Add(new LiteralControl("</table>"));
        }        
        private void InitializeDefaultSettings()
        {
            ibEdit.Attributes.Add("id", "ibEdit");
            ibEdit.Height = Unit.Pixel(24);
            ibEdit.Width = Unit.Pixel(24);
            ibEdit.AlternateText = "Zmenit";
            ibEdit.Attributes.Add("OnClick", "return onEditClick();");

            ibCancel.Attributes.Add("id", "ibCancel");
            ibCancel.Height = Unit.Pixel(24);
            ibCancel.AlternateText = "Zrušit zmenu";      
            ibCancel.Attributes.Add("OnClick", "return onCancelClick();");

            ibOK.Attributes.Add("id", "ibOK");
            ibOK.Height = Unit.Pixel(26);
            ibOK.AlternateText = "Potvrdit zmenu";
            ibOK.Attributes.Add("OnClick", "return onOKClick();");

            txtName.Attributes.Add("id", "txtName");
            txtName.BorderColor = Color.Blue;
            txtName.BorderStyle = BorderStyle.Inset;
            txtName.BorderWidth = Unit.Pixel(1);
            txtName.Width = Unit.Pixel(0);
            txtName.Height = Unit.Pixel(0);
            
            //lblMessage.BorderColor = Color.Blue;
            //lblMessage.BorderStyle = BorderStyle.Inset;
            //lblMessage.BorderWidth = Unit.Pixel(1);

            lblMessage.Attributes.Add("id", "lblMessage");

            lblSucFailText.Attributes.Add("id", "lblSucFailText");
        }
        #region Properties
        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string ControlText
        {
            get
            {
                return _controlText;
            }
            set
            {
                _controlText = value;
            }
        }
        [Bindable(true)]
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        public string ControlPopis
        {
            get
            {
                return _controlPopis;
            }
            set
            {
                _controlPopis = value;
            }
        }
        [Category("Appearance")]
        [DefaultValue("70")]
        [Localizable(true)]
        public Unit ControlWidth
        {
            get
            {
                return _controlWidth;
            }

            set
            {
                _controlWidth = value;
            }
        }
        [Category("Appearance")]
        [DefaultValue("20")]
        [Localizable(true)]
        public Unit ControlHeight
        {
            get
            {
                return _controlHeight;
            }

            set
            {
                _controlHeight = value;
            }
        }
        [Category("Appearance")]
        [DefaultValue("")]
        [Localizable(true)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public string ServiceMethod
        {
            get
            {
                return _serviceMethod;
            }

            set
            {
                _serviceMethod = value;
            }
        }
        [Category("Appearance")]
        [DefaultValue("")]
        [UrlProperty()]
        public string ServicePath
        {
            get
            {
                return _servicePath;
            }

            set
            {
                _servicePath = value;
            }
        }
        #endregion
        /// <summary>
        /// Override of the Control.OnPreRender method
        /// </summary>
        /// <param name="e">Event arguments.</param>
        protected override void OnPreRender(System.EventArgs e)
        {
            if (!Page.ClientScript.IsClientScriptBlockRegistered(typeof(Text2Label),"WebControls.ControlEvents.js"))
            {
                Page.ClientScript.RegisterClientScriptResource(typeof(Text2Label),"WebControls.ControlEvents.js");
            }

            base.OnPreRender(e);
        }   
    }
}

the js file:



function onEditClick(sender, eventArgs) {       
    var r = document.getElementById(''); // the ID of the main control
    if (r != null) alert(r.getAttribute('servicePath')); else alert('nejde');    
    $get("ibEdit").style.visibility = "hidden";
    $get("ibCancel").style.visibility = "visible";
    $get("ibOK").style.visibility = "visible";
    $get("lblMessage").style.visibility = "hidden";
    $get("lblSucFailText").innerHTML = "";    
    $get("txtName").style.visibility = "visible";
    $get("txtName").style.width = $get("lblMessage").style.width;
    $get("txtName").style.height = $get("lblMessage").style.height;
    $get("txtName").value = $get("lblMessage").innerHTML;
    $get("lblMessage").style.width = "0px";
    $get("lblMessage").style.height = "0px";        
    return false;
}

function onCancelClick() {
    $get("ibEdit").style.visibility = "visible";
    $get("ibCancel").style.visibility = "hidden";
    $get("ibOK").style.visibility = "hidden";
    $get("lblMessage").style.visibility = "visible";
    $get("txtName").style.visibility = "hidden";
    $get("lblMessage").style.width = $get("txtName").style.width;
    $get("lblMessage").style.height = $get("txtName").style.height;    
    $get("txtName").style.width = "0px";
    $get("txtName").style.height = "0px";
    return false;
}

function onOKClick() {    
    Store2SQL();
    $get("ibEdit").style.visibility = "visible";
    $get("ibCancel").style.visibility = "hidden";
    $get("ibOK").style.visibility = "hidden";
    $get("lblMessage").style.visibility = "visible";
    $get("txtName").style.visibility = "hidden";
    $get("lblMessage").style.width = $get("txtName").style.width;
    $get("lblMessage").style.height = $get("txtName").style.height;
    $get("lblMessage").innerHTML = $get("txtName").value;
    $get("txtName").style.width = "0px";
    $get("txtName").style.height = "0px";
    return false;
}

function Store2SQL() {
    var r = document.getElementById('');// the ID of the main control
    //if (r != null) alert(r.getAttribute('servicePath') + ', ' + r.getAttribute('serviceMethod') + ' ' + r.getAttribute('controlText')); else alert('je to null');
    Sys.Net.WebServiceProxy.invoke(r.getAttribute('servicePath'), r.getAttribute('serviceMethod'), false, { "prefixText": r.getAttribute('controlText') }, onSucceded, onError);
}

function onSucceded(result, eventArgs) {
    if (result == 0)
    {
        $get("lblSucFailText").style.color = "Green";
        $get("lblSucFailText").innerHTML = "Dáta uložené."; //data stored
    }
    if (result == 3) {
        $get("lblSucFailText").style.color = "Red";
        $get("lblSucFailText").innerHTML = "Dáta neboli uložené!!!"; //didnt store data
    }
}

function onError(error) {
    $get("lblSucFailText").style.color = "Red";
    $get("lblSucFailText").innerHTML = "Dáta neboli uložené: "+error.get_message();    
} 

this is compiled into DLL and attached to ASPX

and the ASPX page:

<%@ Register Assembly="WebControls" Namespace="WebControls" TagPrefix="cc1" %>

<body>
    <form id="form1" runat="server">
    <div>
        <cc2:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
        </cc2:ToolkitScriptManager>
        <cc1:Text2Label ID="Text2Label1" runat="server" ServicePath="WebService1.asmx" ServiceMethod="HelloWorld" ControlWidth="200" ControlText="Default texteee" ControlPopis="Nejaka komponenta aaa"/>
        <cc1:Text2Label ID="Text2Label2" runat="server" ServicePath="WebService1.asmx" ServiceMethod="HelloWorld" ControlWidth="200" ControlText="Default text" ControlPopis="Nejaka komponenta"/>        
    </div>
    </form>
</body>

Open in new window

0
 
KendzastAuthor Commented:
Hi

Thanks thats it.

Actually the correct syntax is

ibEdit.Attributes.Add("OnClick", "return onEditClick('" + this.ClientID + "');");

but that is the solution. I swear I have tried this before, but I must to forget something.

I didnt know that a Web User Control is something else that a Server Control, I figured it out a few days ago and certainly I will try it.

Thanks again.  
0
 
Alexandre SimõesManager / Technology SpecialistCommented:
Sorry about the missing quotes.
As for the web user controls,they are much easier to build,you design them as you design a normal web page.
Do consider using them.

Cheers mate!
0
All Courses

From novice to tech pro — start learning today.