Working with C# .NET 4.0 and Umbraco
I have a user control on which there is a button allowing user to dynamically add additional text boxes to the form. I've tried a myriad of methods but have been unable to persist any data entered into the dynamic text boxes between page loads.
Here's the UI:
<div id="new-item">
<h3>Add new menu item</h3>
<div><label for="ItemTitle">Title</label><asp:TextBox ID="ItemTitle" runat="server" CssClass="title"></asp:TextBox></div>
<div><label for="ItemDescription">Text</label><textarea id="ItemDescription" runat="server" rows="5" cols="20"></textarea></div>
<div><label for="ItemPrice">Price</label><asp:TextBox ID="ItemPrice" runat="server" CssClass="price"></asp:TextBox></div>
<div class="new-item-options">
<p><strong>Menu item options (optional) </strong><asp:Button ID="AddMenuItemOption" runat="server" Text="Add Option" OnClick="AddOption" /></p>
<asp:Panel ID="MenuItemOptionsPanel" runat="server"></asp:Panel>
<asp:HiddenField ID="ItemOptionCount" runat="server" />
</div>
<div><asp:Button ID="AddItemButton" runat="server" Text="Save" /></div>
<asp:HiddenField ID="ItemID" runat="server" />
<asp:HiddenField ID="ItemOrder" runat="server" />
And in the AddOption button click event:
protected void AddOption(object sender, EventArgs e)
{
var dynamicControlCount = Convert.ToInt32(ItemOptionCount.Value) + 1;
for (var option = 0; option < dynamicControlCount; option++)
{
MenuItemOptionsPanel.Controls.Add(new Literal { ID = "OptionTextLiteral" + option, Text = "<label>Option Text</label>" });
MenuItemOptionsPanel.Controls.Add(new TextBox { ID = "OptionTextBox" + option });
MenuItemOptionsPanel.Controls.Add(new Literal { ID = "OptionPriceLiteral" + option, Text = "<label>Option Price</label>" });
MenuItemOptionsPanel.Controls.Add(new TextBox { ID = "OptionPriceBox" + option });
}
ItemOptionCount.Value = dynamicControlCount.ToString();
}
I know I need to create these dynamic controls in the Page_Load or OnInit methods but the problem is when the page loads for the first time, I don't want any dynamic controls create, only once the user clicks the button each time I'm like additional control added and those that already exist to have any data in them persisted.
Any ideas? I don't think I'm too far off hopefully :)
Can you test the confition (perhaps IsPostback) in page_load, then if you need to generate the controls, do it?
Perhaps you have to look at this (series of) article. It explains in details how to work with dynamically created controls, especially about how to persist ViewState.
Otherwise, I would suggest you to go the AJAX way (create controls using JavaScript, post the data back to server using AJAX for the server to process). In this case, you do not have to worry about PostBack and ViewState, and it makes the user experience better too!
Related
I'm currently trying to create a web based wizard tool. I have a Wizard page that contains navigation buttons and an asp panel that will contain the individual wizard panels.
<asp:Panel ID="wizardControlPanel" runat="server">
<!-- Wizard panel goes here -->
</asp:Panel>
<asp:Button ID="backButton" runat="server" Text="< Back" OnClick="BackButton_Click" />
<asp:Button ID="nextButton" runat="server" Text="Next >" OnClick="NextButton_Click" />
<asp:Button ID="cancelButton" runat="server" Text="Cancel" PostBackUrl="~/"/>
One control dynamically fills a checkboxlist
<asp:Label ID="Title" runat="server" Text=""></asp:Label>
<asp:Label ID="DescriptionLabel" runat="server" Text ="Description for the wizard"></asp:Label>
<asp:CheckBoxList ID="ProjectSelector" runat="server" DataTextField="ProjectName" DataValueField="Id" ></asp:CheckBoxList>
I dynamically load this control into my wizardControlPanel once the checkbox is populated.
WizardControl = (BaseWizardControl)LoadControl(("~/Views/" + e.ControlType.Name + ".ascx"));
wizardControlPanel.Controls.Add(WizardControl);
The problem is; on postback I then need to be able to find out which checkboxes were checked server side, but the control no longer exists.
I can't find it on the _page variable. Running in to problems (I think) because I am adding the control to a content holder. How can I get this control back?
It is there, you just won't be able to access it using an ID. You'll need to find it by looking through the wizardControlPanel.Controls collection. I think there is a property that represents the filename you used. But it would be best to use the debugger to track down either where it is in the collection or an identifier you can use to find it.
Having done this once or twice, I think I also remember that you'll need to recreate the control prior to the OnLoad event of the life cycle so that the postback will be able to populate it.
As Markus says, there is probably a better way to do what you are trying to do. But if you MUST load this dynamically, this is how you should go about locating it.
If you add controls dynamically in ASP.NET WebForms, you need to re-add them manually very early in the page lifecycle of the PostBack (e.g. by overriding OnInit and creating the control with the same id in this code) in order to be able to retrieve the values. See this link for a How-To.
The following sample shows the basic steps. It consists of an ASPX-page that contains a Panel as a placeholder:
<asp:Panel ID="wizardPanel" runat="server">
</asp:Panel>
<asp:Button ID="btn" runat="server" Text="Do a postback" />
<br />
<asp:Label ID="lbl" runat="server" />
This is the codebehind-file:
public partial class DynamicUserControls : System.Web.UI.Page
{
protected UserControl userCtrl;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (Page.IsPostBack)
CreateUserControl();
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
CreateUserControl();
else
{
lbl.Text = "The following values were selected: " + string.Join(", ", ((IGetSelectedValues)userCtrl).SelectedValues);
}
}
private void CreateUserControl()
{
if (Request["UserCtrl"] == "A")
{
userCtrl = (UserControl) LoadControl("~/MyUserControlA.ascx");
userCtrl.ID = "myUserCtrl";
wizardPanel.Controls.Add(userCtrl);
}
else if (Request["UserCtrl"] == "B")
{
userCtrl = (UserControl)LoadControl("~/MyUserControlB.ascx");
userCtrl.ID = "myUserCtrl";
wizardPanel.Controls.Add(userCtrl);
}
}
}
The basic steps are the following:
The page determines the user control type to be created upon a Request parameter during Page_Load (or later if necessary). It assigns the ID myUserCtrl to the UserControl.
Upon a PostBack, the page inspects the Request parameters again and re-creates the UserControl with the same ID myUserCtrl. This is important so that ASP.NET can retrieve the new values of the control from the postback data after the page initialization phase. The hardest part is usually to decide which user controls to create, because the data that are available in OnInit is usually not too many.
In Page_Load, the user control can be accessed and the values that were posted back are available. The UserControls in the sample contain a CheckBoxList and implement an interface that allows to retrieve the values that were selected by the user.
In most cases it is easier to find a different approach. Maybe you can use a MultiView control for your wizard that contains the UserControls for the wizard pages as static content. See this link for a description of how to use the MultiView control. If there are not too many (read unlimited) different UserControls to use, this approach is much more stable.
I was looking in the wrong place. Page.Form as opposed to Page.Request.Form. Due to the fact the checkboxlist is already defined in the user control, it's name is traceable in this variable. This way I can keep the current wizard structure.
My html.
<input id="rdb1" type="radio" name="rdbData" checked="checked" />
<input id="rdb2" type="radio" name="rdbData" />
<asp:Button ID="btnTest" runat="server" Text="Test" OnClick="btnTest_Click" />
Button is only asp:button but radio buttons are not.First time when page is load rdb1 is selected.But when i click the button btnTest with check rdb2, page is refreshed and select 1st redio button.To prevent this i try jquery like this.
Inside Document.ready:
var btnTest = "<%=btnTest.ClientID %>";
$('#' + btnTest).bind("click", function() {
if ($('#rdb1').attr("checked")) {
$('#rdb2').attr("checked", false);
$('#rdb1').attr("checked", true);
}
else {
$('#rdb1').attr("checked", false);
$('#rdb2').attr("checked", true);
}
});
But its not work.How can we handle this type of situation.Where i am getting wrong.Any idea or any alternative.Thanks.
If that is the request I would suggest you have a hidden field (server side) which will keep the state of which input radio button is selected (use jquery to update the hidden field when user clicks on the radio buttons). Then on postback as the hidden field is set at runat="server" it will maintain its value (viewstate) and you can simply use jquery to set the right radio button as selected. Does that make sense ?
I repeat that the requirement is ABSURD. How are they going to tell you used server-side controls without looking at the code anyway. This is like requiring that you write the code using chopsticks or something.
However just as an exercise I provide the following solution:
<input id="rdb1" type="radio" name="rbdData" value="rbd1" <%= Rdb1Checked %> />
<input id="rdb2" type="radio" name="rbdData" value="rbd2" <%= Rdb2Checked %> />
<asp:Button ID="btnTest" runat="server" Text="Test" onclick="btnTest_Click" />
And the code behind:
protected string Rdb1Checked
{
get
{
if (IsPostBack)
{
if (Request["rbdData"] == "rbd1")
{
return "checked";
}
else
{
return "";
}
}
return "checked";
}
}
protected string Rdb2Checked
{
get
{
if (IsPostBack)
{
if (Request["rbdData"] == "rbd2")
{
return "checked";
}
else
{
return "";
}
}
return "";
}
}
Ask why they have these requirements. Maybe they don't want to see the client IDs in which case you may set the ClientIDMode to Static and avoid auto generated IDs. You can remove them completely by setting them to null, etc. Maybe they don't like what Web Forms renders for Radio buttons in which case using server side inputs would be OK. The requirement on its own simply does not make sense.
Shree
The fact is that client click (added by jQuery) executes before the call to server. If you want to persist the selectin, try using server sided controls:
<input id="rdb1" type="radio" name="rdbData" checked="true" runat="server" />
<input id="rdb2" type="radio" name="rdbData" runat="server" />
<asp:Button ID="btnTest" runat="server" Text="Test" OnClick="btnTest_Click" />
Try this if it does work for you.
Hope it helps.
When the "Test" button is clicked, the page posts back to the server, which re-renders all client-side controls just as if the page has been loaded for the first time. Since the entire page is reloaded, jQuery will also "forget" about the state of the controls, so that approach won't work either. The simplest way to prevent this is to ensure the radio buttons run on the server side. For instance:
<asp:RadioButton id="rdb1" Checked="True" GroupName="RadioGroup1" runat="server" />
<asp:RadioButton id="rdb2" GroupName="RadioGroup1" runat="server" />
Hope that helps!
What do you mean? That you have a requirement that does not let you use "servr side controls" or that your IDE does not allow that?
By definition, in ASP.NET all HTML controls inherit from a server control. Simply adding runat="server", you can access that control from codebehind, although it will still render in page as a normal HTML control.
I want to load data in second <select> tag (in ASP.NET) when I select an item from first <select> tag.
I have :
<table cellpadding="2" border="0">
<tr><td>Categories : <br /><select id="list_cat_for_list" runat="server" onchange="get_list" ></select><br />
<select id="list_got_links" runat="server"></select>
</td><td><asp:RequiredFieldValidator ID="RequiredFieldValidator1" ControlToValidate="list_cat_for_list" ValidationGroup="del_cat" Display="Static" runat="server" ErrorMessage="select category"></asp:RequiredFieldValidator></td></tr>
<asp:Button runat="server" ID="Button1" OnClick="delete_category_function" Text="Delete category" ValidationGroup="del_cat" />
</table>
And the code behind :
protected void get_list( object sender, EventArgs e ) {
BusinessLayerArcht layer = LoadDataFromBL();
foreach ( CategoriesCtrlDto cto in layer.Categories ) {
if ( cto.Name == list_cat_for_list.Value ) {
foreach ( LinksCtrlDto lk in cto.Links ) {
list_got_links.Items.Add( lk.Url );
}
}
}
}
When I change option, IE returns that get_list is undefined.
I don't know what arguments I have to pass to C# function.
I know that onClick has object sender, EventArgs e...
Where is my mistake ?
You can use the ASP Drop down list to perform this aciton on the server side.
<asp:dropdown id = "id" runat="server" selectedIndexChanged="get_list"><asp:dropdownlist>
If you need to access the client side version of the control in javascript you can utilize the browser's "view source" feature to get the ASP generated ID for the control and use that for referencing in any javascript.
If you wish to use AJAX there's an extender in the AJAX Control Toolkit which allows you to perform the cascading drop down feature with multiple dropdowns asynchronously so you won't have the complete postbacks going on while the user is interacting with the page.
You can download the toolkit for free from Here
Why don't you use the asp.net drop down list instead of the html select. Both will be rendered as select element but it will be easier for you to use the drop down list chnage event handler
I have text boxes and it has values let say. I am calling my javascript method on one of textbox 'onblur'. my function is:
function CalculateExpectedProductPrice() {
alert("hi i called");
var originalPrice = document.getElementById('hdnSelectedProductPrice').value;
var numberOfLicenses = document.getElementById('txtNumberOfLicense').value;
var enteredAmount = document.getElementById('txtAmount').value;
alert(originalPrice);
alert(numberOfLicenses);
alert(enteredAmount);
}
i am getting alert message as ""hi i called". but not further.
But some i am not getting values of these controls.
*Edited:* My HTML is :
<asp:HiddenField ID="hdnSelectedProductPrice" runat="server" />
<asp:TextBox ID="txtAmount" runat="server" Width="250px"></asp:TextBox>
<asp:UpdatePanel ID="UpdatePanel2" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:TextBox ID="txtNumberOfLicense" runat="server" Width="35px" ></asp:TextBox>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="txtNumberOfLicense" EventName="" />
</Triggers>
</asp:UpdatePanel>
Will there any impact master-content page . because script is in content page and html also on same content page.Also let me know you, I am using wizard control where as all these controls are resides on second step of wizard. will that make any impact ?
Edited:
I think wizard control making here matter. As i started my firebug and review the generated html it assign the Id dynamically to those controls which are inside the wizard. thats why javascript unable to find the expected control .
eg for txtAmount text box which is inside the wizard control getting name as :
ctl00_ContentPlaceHolder1_Wizard1_txtAmount
but certainly i would not prefer to use this generated Id. So is there any remedy to find control inside the wizard control and get - set values ?
get id of the control as shown below
var enteredAmount = document.getElementById('<%=txtAmount.ClientId%>').value;
It's impossible to say for certain with your not having quoted your HTML (!), but the usual reason for this is confusion between the id and name attributes. document.getElementById works with the id attribute, but people tend to think it works with the name on input fields, which it doesn't (except for on IE, where getElementById is broken).
(The other thing to remember is that id values must be unique on the entire page, but looking at the IDs you quoted, I suspect you're okay on that front.)
Update: It works if you use ids:
HTML:
<form>
<input type='hidden' id='hdnSelectedProductPrice' value='10'>
<input type='text' id='txtNumberOfLicense' value='2'>
<input type='text' id='txtAmount' value='3'>
<br><input type='button' id='theButton' value='Click Me'>
</form>
Live copy
As T.J. mentioned we really need to see your html code, without seeing it it could be that you are looking for an elements attributes.
So lookup the element as you are already with
var element = document.getElementById('product');
Once you have the element you can query its attributes
var price = element.getAttribute('price');
If its "ASP.net server control" then you will have to do it like this:
var originalPrice = document.getElementById('<%=hdnSelectedProductPrice.ClientID %>').value;
if you use Asp.Net 4.0 and your textbox is unique on the entirepage you can add ClientIDMode="Static" in attribute of your textbox
<asp:TextBox ID="txtAmount" runat="server" Width="250px" ClientIDMode="Static"></asp:TextBox>
I need to display a control consistently across a set of pages. So I'm using a MasterPage to do that in ASP.NET/C#. However I also need to programmatically access this control, mostly provide options to view/hide depending on whether the controls checkbox is clicked.
Here is the Source for the MasterPage
<div id="verifyInitial" runat="server">
<asp:CheckBox ID="chkInitialVerify" runat="server"
oncheckedchanged="chkInitialVerify_CheckedChanged" />
I agree that my initial data is correct.
</div>
<div id="verifyContinuous" runat="server">
<asp:CheckBox ID="chkContinuousVerify" runat="server"
oncheckedchanged="chkContinuousVerify_CheckedChanged" />
I agree that my continuous data is correct
</div>
Now in the code behind I want to perform the following operations. Basically if a person clicks on the checkbox for the initial div box, then the initial box disappears and the continous box shows up. However it seems that the code behind for the MasterPage does not activate whenver I click on the checkbox. Is that just the way MasterPages are designed? I always thought you could do add some sort of control functionality beyond utilizing the Page Load on the Master Page.
protected void chkInitialVerify_CheckedChanged(object sender, EventArgs e)
{
verifyContinuous.Visible = true;
verifyInitial.Visible = false;
}
protected void chkContinuousVerify_CheckedChanged(object sender, EventArgs e)
{
verifyContinuous.Visible = false;
}
If you're expecting the two controls to trigger a change for that page immediately then you'll need to set the AutoPostBack property to true for both of them:
<div id="verifyInitial" runat="server">
<asp:CheckBox ID="chkInitialVerify" runat="server" oncheckedchanged="chkInitialVerify_CheckedChanged" AutoPostBack="true" />
I agree that my initial data is correct.
</div>
<div id="verifyContinuous" runat="server">
<asp:CheckBox ID="chkContinuousVerify" runat="server" oncheckedchanged="chkContinuousVerify_CheckedChanged" AutoPostBack="true" />
I agree that my continuous data is correct
</div>
Otherwise, you need an <asp:button /> or some other control on the page to trigger a postback and cause your event handlers to run. The button, or other control, can either be on your masterpage or on your content page, the choice is entirely yours.