I have a UserControl with two labels and a slider control on it. I have a javascript function that is called when the value of the slider changes, and it is supposed to update the text of the labels.
The ascx code is:
asp Code:
<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="AlignSlider.ascx.vb" Inherits="F1TimeTrials.Controls.AlignSlider" %>
When I put this control on a page it works just fine. I drag the slider, the labels update with the new values.
However, I actually need a large number of these controls on my page (around 10-20 I think), and this is where the problems start. When I change the slider on one of these UserControls, it changes the text of only the labels in the LAST instance of this UserControl on the page. It seems that the 'document.getElementById' function actually searches through the entire page rather than just the one UserControl.
How can I fix this? How can I get the two label controls from this current UserControl instance, and not any other instance on the page?
I don't know what you mean. My UserControl has two labels as you can see, one called lblLeftValue and one lblRightValue. I am simply putting multiple of these UserControls on one page.
var leftLabel = document.getElementById('<%= Me.lblLeftValue.ClientID %>');
var rightLabel = document.getElementById('<%= Me.lblRightValue.ClientID %>');
get the id's of the last two labels in the page (check out the markup)
what you need to do is to pass the labels id's of the target control each time you call the sliderControl_ValueChanged method.
there are number of ways to do so, the easiest way is using jQuery but no doubt you can do it with native js, if you using .NET FW 4 you can control how the ids of your controls is rendered and use the Predictable value of the ClientIDMode property otherwise you can just check the markup and see how the the labels is been rendered.
if you still need help please paste to here the html markup
But the labels are on the UserControl! How can I pass in the 'target control' (that would be the current instance of that UserControl) if I am in that UserControl... The only reference I can think of is "Me" and I'm already using that.
Regardless of the number of the UserControls that get placed on the place, the ClientID of the controls on the page should all be unique. Typically, this means that the name of the parent control will be appended to the front of the label controls within the page.
Nick, as a first step, add two user controls to your page, and then inspect the HTML. Are you getting unique ID's for each of the two labels within the user controls?
Ok, I placed three sliders on a test page. Two of them (slider1 and slider2) are NormalSliders, and one if them is a BallastSlider. The difference is minimal, both of them are very similar UserControls with two labels and a WebSlider third party control. The difference is their min/max values and their stepsize (and the fact that one label is hidden for the NormalSlider). You may remember this from my other thread where I tried to let the different sliders inherit one UserControl but I ditched that idea (since it isn't working..) and just made three separate UserControls.
And the resulting HTML is attached because it is way too large.
It's quite a lot, probably because the sliders consist of separate images too make them look nice I guess, but the one thing I can see is that the label names in the javascript do indeed refer to the parent UserControl. For example, in the second slider UserControl javascript code I can spot
Code:
var leftLabel = document.getElementById('ctl00_MainContent_slider2_lblLeftValue');
var rightLabel = document.getElementById('ctl00_MainContent_slider2_lblRightValue');
This is slider1 and ballastSlider for the other two, so I'm a little mystified why it still updates the last labels only...
var leftLabel = document.getElementById('<%= Me.lblLeftValue.ClientID %>');
var rightLabel = document.getElementById('<%= Me.lblRightValue.ClientID %>');
won't work, cause you need to use multiple controls in your page.
what you need to do is to get first the control id which i beleive you can get it with the sender object (did you tried what i wrote in my other post?)
and then use it as the label id, it should be something like this:
if the control id is: ctl00_MainContent_slider2_table
then this is how you'll get the wanted labels IDs:
Code:
<script type="text/javascript" id="igClientScript">
<!--
function sliderControl_ValueChanged(sender, eventArgs) {
var objectID = sender.id;
var leftLabelID = objectID.substring(0,26) + 'lblLeftValue';
var rightLabelID = objectID.substring(0,26) + 'lblRightValue';
var leftLabel = document.getElementById(leftLabelID );
var rightLabel = document.getElementById(rightLabelID);
var maxValue = sender.get_maxValueAsDouble();
var value = eventArgs.get_newValue();
leftLabel.innerHTML = value;
rightLabel.innerHTML = maxValue - value;
}// -->
</script>
Hmm I will try that later, but it doesn't seem like a very solid approach. Substring(0, 26)..? What if the control name ctl392 or whatever? Then that will go wrong already. There must be a simple way to get the label on the current UserControl instance :/
This is the reason i would use jQuery for this task, until FW 4 ASP.NET developers had really big problem with html elements IDs when javascript was involved, i did suggest in early posts to set the clientidmode to Predictable, anyways the method i suggested is not very "good looking" but it will work flawless because of the single fact that the label controls id and the slider controls id will always start the same and only end differently.
I noticed the sender object in the function. Did you try to use that client id ?
The sender is the object that called the javascript function, eg the WebSlider third party control. I dunno what that helps me retrieve the labels. The only connection the labels and the WebSlider have is that they are on the same UserControl.
Ok, I still don't get it... sender.id doesn't work, if I put that in an alert it tells me 'undefined'.
Let's make it easier, forget about the sliders. Here's a much simpler UserControl: a Button and a label. When the button is clicked, it adds a | character to the label, so you can see how many times it's been clicked:
asp Code:
<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="ButtonUserControl.ascx.vb" Inherits="F1TimeTrials.ButtonUserControl" %>
<script type="text/javascript">
function buttonClicked() {
var label = document.getElementById('<%= Me.label.ClientID %>');
Click both buttons. As you can see, both buttons add | characters only to the LAST UserControl's label.
Could you show me how I can fix this? There is no sender in this case (at least I don't think so?), all I have is the current UserControl instance, and I would expect "Me.label.ClientID" to return the correct label's ID and not the ID of the last label, irregardless of which UserControl instance it is on...
In the first script, it references the first label. In the second script, it references the second label. Yet, it always changes the second label.... ***?
Last edited by NickThissen; Nov 12th, 2010 at 08:36 AM.
few things to note:
A) you should write the JS function outside the usercontrol because then you get multiple identical function which could lead to problems.
B) i too don't like the substring method but it work, again use jQuery selectors which make js + asp.net very easy or upgrade to FW 4.0 and then you can control of how your html elements be rendered ...
Could you explain how to use jQuery and/or FW 4.0? I think I have both... I don't like to use the substring approach (unless it is common practice?!) as it just seems very 'unstable' and might break at any time if I change something... The number 31 for example, why is it 31 while it was 26 last time? How do you know that it will be 31 always?
i only changed the javascript function (you must add jQuery library to use it: http://www.jquery.com
the first line does all the job let me explain
Code:
var label = $(obj).parent().parent().find('span:eq(0)');
obj is the button instance, the button element is child of table cell and the table cell is the child of table row and the label is actually a span element inside another table cell
so with jquery selector you can drill upword to the table row and then use the
.find() method to get to the first span elements ":eq(0)" selects the first one
Doesn't seem to work, when I put an alert after the 'var label =' line it never reaches it. Do I have to install jQuery or something? I automatically get a folder Scripts with some jQuery files in it in my project so I assumed it was ok..?
Now, still no alert, but the page no longer posts back. This is a little strange to me... If it doesn't post back then it has reached return false right? But why then is there no alert? And no extra |...?
I don't get it, why is this so hard? When I search for 'multiple user controls' I get at least 5-6 results with people having the exact same issue, but all they got was a few vague hints but no real solution... I don't understand how something this fundamental can be so difficult to accomplish :s
Last edited by NickThissen; Nov 13th, 2010 at 05:40 AM.
you should be more stubborn, if something not work and it should you really try to find the reason of why it's not working, anyway in FW 4 every control has the property ClientIDMode, you can set its property to
predictable and then use the first method i showed you but without the substring but using its index.
now, if this makes you wanna quit ASP.NET then you really should cause there are a lot more to come, unlike win apps (win forms) web developers need to deal with browsers compatibility, master lots of languages (c#/vb,js,css,html,sql,jq,ajax,linq) and more... my advice don't quit, you just might trying something that is bit advanced for you at the moment, keep learning and i'm sure you'll get there quickly.
The ClientIDMode doesn't need to be set to Predictable, as its default is Inherit and the page (from which it inherits) should default to Predictable. So, if my logic is correct, it should already be Predictable by default.
It makes me want to quit ASP.NET because it simply isn't logical. If I get the ClientId of Me.lblLeftValue then it should return the ClientId of Me.lblLeftValue, and not of some other label on the page. That just makes absolutely no sense to me.
If i'm not mistaken the default clientidmode is AutoID.
and what happen to you makes a lot of sense, each control have to have unique ID so if you have two labels each of of them got to have its own ID, when working on the client side (javascript) you don't have the benefits of working on the server side where the compiler do the job for you and find the correct id for you just by using the original id name of the control
But look at the HTML I posted a few posts back. The labels do have unique IDs. The first one is called ctl00_MainContent_ctl00_label, and this is also what it says in the first javascript code. The second one is called ctl00_MainContent_ctl01_label and that's also what it says in the second javascript code.
And from MSDN:
The default value of ClientIDMode for a page is Predictable. The default value of ClientIDMode for a control is Inherit. Because the default for controls is Inherit, the default generation mode is Predictable. (However, if you use Visual Studio to convert a Web project to ASP.NET 4 from an earlier version, Visual Studio automatically sets the site default to AutoID in the Web.config file.)
As far as I know I didn't convert my project, I just started a new Web Application in ASP.NET 4, so my default ClientIDMode should be Predictable.
yes the labels do get unique ids and this is the reason you can't use the same id name for each label.
the blame for you problem is the author of the control you're using, he/she should have supply methods to handle this situation.
my advice is you won't give up using jQuery, I checked the example that i posted here and it's working beside that jQuery will help you a lot more along the way.
if you're using firefox d/l firebug plugin this is great tool for debugging javascript errors, if you're using ie or chrome they both have js debugger as well, but i still go with firebug.
you can post here the exact code that don't works for your with jquery and i'll try to recreate the problem.
Ok, I am trying to play catch up with this thread, and I am failing...
Where exactly are we at? Nick, can you post a sample of the application as it stands, so that we can try and help?
Also, I would strongly encourage you not to give up on ASP.Net. I agree that some things don't make sense at the start, but a lot of that will be because you come from a Windows Application background, and the paradigms are completely different.
I am still stuck at post 27 I guess. Trying to have a Button click add a | character to a label. The code you see there is, as far as I can see, identical to what motil gave me, yet it's not working. The page does not post back (good), but the alert does not show and the | doesn't come up.
Nick i just re-checked your code.. the reason it's not working for you is that you changed the parameter name but didn't changed it inside the code look:
Code:
function buttonClicked(sender) {
var label = $(obj).parent().parent().find('span:eq(0)');
alert('jup');
label[0].innerHTML += '|';
return false;
}
decide how you wish to call it "obj" or "sender" but it must be the same..
this is why you need js debugger btw..