I'm currently working on an ASP.NET 3.5 project, and I wanted to know your opinion regarding the following situation, which I happen to run into sometimes:
Let's say I've defined the following control of an imaginary component framework somewhere in my code:
<Window runat="server" ID="windowTest" />
Let's assume that with the above mentioned imaginary component framework it's possible to get a reference to my Window control from the client-side using its ID (for example to change its appearance):
function MyFunc(){
var win = GetWindow("windowTest");
}
Let's also assume that both code snippets are placed in different files, e.g. the JavaScript code in MasterPage.Master and the control in AnotherPage.aspx.
As you might already have noticed, the passing of the control's ID as a hard-coded string to the GetWindow function is a bit problematic here, since changing the control's ID is going to break the JavaScript function.
This situation surely smells like it needs a good ol' Replace Magic Number with Symbolic Constant refactoring. I can achieve this by dynamically creating the Window control and using a constant for the value of the control's ID:
AnotherPage.aspx:
Window windowTest = new Window();
windowTest.ID = Consts.ID_WINDOW_TEST;
form1.Controls.Add(windowTest);
MasterPage.Master:
function MyFunc(){
var win = GetWindow("<%= My.Namespace.Consts.ID_WINDOW_TEST %>")
}
My question now is: How do you handle such situations? Do you create all your controls dynamically (like shown in the example above) when running into this situation, and are there any drawbacks using this approach, e.g. Designer doesn't display the control anymore? Or do you say "Screw it, nobody's going to change that control's ID" and leave it hard-coded in your code? Or do you have other approaches to this situation?
I personally am a fan of the of the first option (refactoring), since a) it makes sure that a change to the ID is not going to break my code and b) I almost never work with the Designer, but I thought I'd ask this question on SO to get some valuable opinions on this.
Thanks in advance for all the responses.
Greetings,
Giu
Update / Clarification:
I made a small error in the first version of this question by stating that the code snippets are placed in the same file. Since both the control and the JavaScript method are located in the same file, there is no need to create the control dynamically and defining the control's ID using a constant; by defining the control directly in the .aspx file I could use its ID in the JavaScript method as follows: GetWindow("<%= windowTest.ID %>");
But, my problem is another one; the control and the JavaScript method are each placed in different files, in which case the mentioned approach of using the control's ID doesn't work anymore. Therefore I introduced the solution mentioned in my question with the constant and the dynamic creation of the control. I now corrected both the filenames in my question so that the correct scenario is described to which my question is related.
In 4.0 you can control the client ID that's generated in master/content page situations quite well. but i believe if someone changes the ID manually in the page at one place and not in the javascript code it will still be a problem. If you are the only one who'll be working on this code then you can always be mindful and refactor properly. Otherwise you can go in for the constants option or store the IDs in a separate resource file.
In my opionion there a two suitable solutions:
1) Use the JQuery framework to get ahold of the html element you want to adress via JavaScript. JQuery is designed to be able to work with autogenerated hierarchically created control IDs
2) Use .net Framework 4.0 and don't use autogeneration of the Control ID. (I've heard that this is a new feature in 4.0. I think in your situation it might be worth trying out)
Check out Rick Strahl's blog post entitled "A generic way to find ASP.NET ClientIDs with jQuery"... it seems to have some good ideas that could be of some help to you.
He uses jQuery, as the first responder suggested, but does it in a way that you are using ASP.NET's built-in ClientID property to get the actual id ASP.NET generates and uses a client-side friendly mechanism that enables you to write script code referencing controls that won't break with ID changes.
Related
I'm newbie in ASP.NET and i think that my question is quite simple, but I'm not getting success in my searches through google or even stackoverflow.
I have a asp.net method (vb.net) that loads a entire html page inside a div.
Doing searches, i discovered that it can be like this:
On .aspx page:
<div id="content"></div>
On .vb codebehind:
Private sub LoadContent()
content.InnerHtml = MyDLL.LoadFromDatabase.Value.ToString()
End Sub
So, nothing special until here.
But, if consider that the html code loaded from database has form elements like <input id="name" type="text">, my problem starts...
On page postback these don't keep the values as <asp:TextBox> created natively on code, does.
And the other thing that I want is a way to retrieve the value from them to work on codebehind, like: myvar = content.Controls("name").Value
At least, is there a way to solve my problem?
Sorry for my bad english, and thanks so much.
CRice is right. If you want the viewstate to persist through postback you need to create the controls server-side.
Careful though: I've had bad experience with dynamically created controls on Asp.Net, specifically when trying to bind events to them. Not only would you have to use delegates and events (a hard topic for a newbie), also when I tried it a few years ago I just couldn't get it to work, no matter what.
If you're going for dynamic created controls, make sure it's worth the effort, because it WILL be an effort, now and in the future when you would like to maintain and add expand. A rule of thumb is that dynamic mechanisms are always harder to maintain than static ones, but they provide more flexibility.
Having that said, if you're still going for dynamic html loading, be aware that better solutions exist, though they require different architectures: client side frameworks (best is angluar.js) provide dynamic loading of "modules" (and much more), which is what you want. On the server side, asp.net MVC with its Razor view engine, partial views etc., is better suited for dynamic html generation.
Back to your original question,are you sure you need a full postback? What about a nice neat Ajax call to a web service? Can get the job done in many cases without reloading the whole page. I guess using jquery's $.ajax syntax and creating a simple .asmx web service will be easiest for you.
Last but not least, why use vb.net instead of c#? It sucks man. Give it up while you still can.
Could I declare asp.net page method in side Web form code behind file using [System.Web.Services.WebMethod] attribute?
Yes, you can add the code inline if you want - it's pretty messy though. Take a look at this blog post for help. Also, take a look at this MSDN reference for a comparison. There is also another tutorial here.
In my opinion, if you need to use webforms, then you should stick to the code behind model and keep the minimum about of code in there for the event handlers only. Move any business logic, or utility code into separate classes.
I think I summed up the question in the title. Here is some further elaboration...
I have a web user control that is used in multiple places, sometimes more than once on a given page.
The web user control has a specific set of JavaScript functions (mostly jQuery code) that are containted within *.js files and automatically inserted into page headers.
However, when I want to use the control more than once on a page, the *.js files are included 'n' number of times and, rightly so, the browser gets confused as to which control it's meant to be executing which function on.
What do I need to do in order to resolve this problem? I've been staring at this all day and I'm at a loss.
All comments greatly appreciated.
Jason
If the issue is simply that the same file is being embedded multiple times and causing conflict, look into using RegisterClientScriptInclude. If you use the same identifier for all of your calls to RegisterClientScriptInclude only one instance of that file will be embedded:
http://msdn.microsoft.com/en-us/library/2552td66.aspx
However, if the issue is that your methods are being called but they don't know what controls on the page to operate on then you need to figure out how to provide your JS some context. Define a JavaScript object that represents your control on the client-side, and on the server-side emit the call that will instantiate it with the client IDs of the controls you'll be operating on.
We are using CustomValidator to validate User Control. The control works fine until you drop two instances of the Control on the same page, since they reference the exact same JavaScript functions, only one control works. Work around, we appended JavaScript function name with control id.
Validate_SAPDepartment<% =ControlId %>(oSrc, args) {...}
In codebehind, we assinged ClientValidationFunction
CustomValidator1.ClientValidationFunction = "Validate_SAPDepartment" + this.ControlId
This may not be the right approach but it works.
I've had this situation before. You register a separate JavaScript file with the page using the ScriptManager. You can stream this as a resource file embedded into the dll if you wish.
Then you only call into the functions from your control.
Otherwise a completely separate jquery file may also work.
I am creating a completely custom (only inherits from WebControl) combobox/dropdownlist search control with autoComplete capabilities.
JQuery handles assigning the onhover and onclick events for list items (divs with strings in them) and handles the web service call for getting the list of items for the matching text.
The server handles the custom attributes and control rendering.
The issue is that I need to implement a property that is similar to SelectedValue so that when a user selects an item from the search results, the value can be used on the server for other processing. I have done days of research but have not found a clear, concise way of handling the post back data.
I did read a blog that mentioned implementing the IPostBackDataHandler interface, but the implementation of RaisePostDataChangeEvent() calls for calling a server method (like SelectedIndexChange) that I am not implementing at the moment.
public void RaisePostDataChangedEvent()
{
this.SelectedIndexChanged(EventArgs.Empty);
}
Now for the question: Does anyone have advice for handling this? Or am I better off simply inheriting from the dropdownlist control and overriding the existing functionality?
I feel like I'm missing a very small piece that will fit this all together.
Have you considered pulling down the source code from Microsoft's source server and taking a look at how they implemented DropDownList? This would allow you so see how they solved the binding and events part of the problem and give you a good idea what it does otherwise. This way you can decide if you want to inherit from it, or if you can just borrow some ideas for how they implemented IPostBackDataHandler.
Since I have no idea what specifically you are doing, I couldn't advise you if you should inherit from dropdown as it is, but based on my impressions of what you are doing I'd say you probably don't.
Also you might look at source from the AjaxControlToolkit as it has a similar component. Again, you can get ideas for how these specific things are handled and adapt them to your own needs.
OK, I am not sure if the title it completely accurate, open to suggestions!
I am in the process of creating an ASP.NET custom control, this is something that is still relatively new to me, so please bear with me.
I am thinking about the event model. Since we are not using Web Controls there are no events being fired from buttons, rather I am manually calling __doPostBack with the appropriate arguments. However this can obviously mean that there are a lot of postbacks occuring when say, selecting options (which render differently when selected).
In time, I will need to make this more Ajax-y and responsive, so I will need to change the event binding to call local Javascript.
So, I was thinking I should be able to toggle the "mode" of the control, it can either use postback and handlle itself, or you can specify the Javascript function names to call instead of the doPostBack.
What are your thoughts on this?
Am I approaching the raising of the events from the control in the wrong way? (totally open to suggestions here!)
How would you approach a similar problem?
Edit - To Clarify
I am creating a custom rendered control (i.e. inherits from WebControl).
We are not using existnig Web Controls since we want complete control over the rendered output.
AFAIK the only way to get a server side event to occur from a custom rendered control is to call doPostBack from the rendered elements (please correct if wrong!).
ASP.NET MVC is not an option.
Very odd. You're using ASP.NET server controls and custom controls, but you're not using web controls? And you're calling __doPostBack manually?
Do you like to do things the hard way?
If I was still using the server control model rather than MVC, I would slap ASP.NET Ajax controls on that sucker and call it a day. What you're doing is like putting a blower on a model T. It may be fun and interesting, but after you're done with all the hard work, what do you really have?
I have been doing some more digging on this, and came across how to inject Javascript in to the client when required. This will obviously play a huge part in making the controls more responsive and less round-trips to the server.
For example: RegisterClientScriptBlock.
Look forward to playing with this more, feel free to get invovled people!