views:

80

answers:

1

I'm attempting to introduce master pages to an existing webforms site that's avoided using them because of client id mangling in the past (and me not wanting to deal with the mangling and doing <% foo.ClientID %> everywhere :)

GOAL: use 'static' id values (whatever is in the server control's id attribute) except for data-bound / repeating controls which would break for those cases and therefore need suffixes or whatever to differentiate (basically, Predictable)

Now that the site migrated to ASP.NET 4.0, I first attempted to use ClientIDMode of Static (in the web.config) but that broke too many places doing repeating controls (checkboxes inside gridviews, for instance) since they all resulted with the same id.

So, I then tried Predictable (again, just in the web.config) so that the repeating controls wouldn't have conflicting id's, and it works well except that the master page content placeholder (which is indeed a naming container) is still reflecting in the resulting client id's (for instance, ContentPlaceHolder1_someCheckbox).

Certainly I could leave the web.config setting as static and then go through all the databound/repeating controls switch them to Predictable, but I'm hoping there's some easier/simpler way to get that effect without having to scatter ClientIDMode attributes in those N number of places (or extend all those databound controls with my own usercontrol that just sets clientidmode, or whatever).

I even thought of leaving web.config set to static and doing a master or basepage handler (preinit? not sure if that would work or not) that would go walk Controls with OfType<INamingContainer>() (might be a better choice on the type, but that seems like a good starting choice looking at repeater and gridview) and then set those to Predictable so I'd get static for all my 'normal' things outside of repeating controls but not have to deal with static inside things like gridview/repeater/etc.

I don't see any way to mark the content placeholder such that it 'opts out' of being included in child id's - setting the ID of the placeholder to empty/blank doesn't work as it's a required attribute :)

At that point I figured there was a better/simpler way that I was missing and decided to ask on SO :)

Edit: I thought about changing all my 'fetch by id' jquery calls from $('#foo') to fetch_by_id('foo') and then having that function return the 'right one' by checking $('#foo').length and then $('#ContentPlaceHolder1_foo').length (and maybe other patterns) or even just have it return $('#foo, #ContentPlaceHolder1_foo') (again, potentially other patterns) but changing all the places I fetch elements by id seemed pretty ugly too, and I'd like to avoid that abstraction layer if possible to do so easily :)

Edit2: WRT using jQuery selector of id$='foo':

my worry doing such a thing (although it may be more imagined than real) is when one of the id's in a page ends with another. For instance, if a page has elements with id's of 'foo' and 'barfoo' then id$='foo' will accidentally include the 'barfoo' as well. Certainly there are plenty of methods for preventing that (like suffixing with the element type, so fooCheckbox and barfooButton or whatever) but I didn't want to have to scan the existing source and/or enforce a new rule for naming.

Since not all of the controls are server controls, I can't $='_foo' either since a normal div id="foo" won't be found (and I'd rather avoid runat="server" just to mangle the name :)

another thing I considered was making a unique css class name per element and selecting on that instead (since class obviously doesn't get mangled) but it's very hacky to do so and certainly muddies things up when doing the 'real' CSS work :)

A: 

I honestly don't know if there is an easy way of doing it, but considering you are using jQuery what I have done in the past is, I used the attribute ends with the selector method.

Since .Net appends your "static" id to the end of it's generated id, you can get that with the jquery selector $("input[id$='yourstaticid']").

I know this is not THE solution that you are looking for but it would make your 'fetch_by_id' simpler.

Hope it helps or gives you an idea at least.

drusnov
added 'Edit2' as a response - certainly reasonable if I indeed go down the fetch_by_id route, but really hoping for something less drastic if possible :) Thanks for mentioning it, though! I certainly should have included that in the initial post :)
James Manning
no problem .. I will keep my eyes posted for a solution, cause it sure would come in handy :)
drusnov
One more thing, on your Edit2, you're saying that you might want to add cssclass names to the elements, but you don't want it to mess the ACTUAL css work .. what if you just append another class to the existing ones, if they exist .. isn't the class selector still going to select the appropriate element .. ie. if you had an element with a <input class="foo bar" />, wouldn't calling $("input.bar") get the element just as $("input.foo")??? this is more of a question I guess, sorry if this was the wrong place to do it in, I am just interested in finding a solution now :))
drusnov
certainly - the intent would be to have 'identifier' css classes (probably named a certain way to make it clear, like 'id_refresh_checkbox', although even that can be confusing) and keep those separate from the 'real' css classes on the elements.However, I couldn't disagree if someone considered that an abomination - certainly it's against the idea of 'classes' to start with.Another very-likely-bad idea (never actually tried it) was to have the first thing in document.ready walk the dom and .attr() to remove ContentPlaceHolder1_ from the id's. No idea if that would even work, though.
James Manning
no better options have shown up, so I'll mark this as answer :)
James Manning
Cool Deal ... thanks ... sorry that I couldn't be more helpful :)) good luck and if you ever figure it out or find an actual solution .. let me know .. I would be interested to see it ...
drusnov