I have the following Javascript code that creates multiple textboxes depending on the number you enter.
function generate() {
var tot = document.getElementById("nrintrebari").value;
var tbl = document.getElementById("sim");
for (var i = 1; i <= tot; i++) {
tbl.innerHTML = tbl.innerHTML + 'Intrebare nr.' + i + ' <input type="text" size = "80" maxlength= "200" name="intrebare[]" style="height:30px; background-color:#B8B8B8; " > <br><br><br> ';
}
}
How can I loop through this form to get all the answers in the textboxes using C#?
Regardless of Webforms or MVC, when a a form is submitted, it will contain all of the fields in the form post data.
You have chosen to dynamically inject N number of elements all with the same name, "Intrebare[]".
When you do this, the form post data will contain one element (actually a key-value pair) called "Intrebare[]", and it will contain all of the values of your dynamically injected textboxes, separated by commas.
I've put together a very small sample of code that should help you get what you need; actually my code sample iterates through the entire form post so you can see all the fields:
First, I created an empty ASP.net Web Forms Application.
<script type="text/javascript">
function generate() {
var tot = document.getElementById("nrintrebari").value;
var tbl = document.getElementById("sim");
for (var i = 1; i <= tot; i++) {
tbl.innerHTML = tbl.innerHTML + 'Intrebare nr.' + i + ' <input type="text" size = "80" maxlength= "200" name="intrebare[]" style="height:30px; background-color:#B8B8B8; " > <br><br><br> ';
}
}
</script>
<input id="nrintrebari" type="text" value="10" />
<div id="sim">
</div>
<input type="submit" value="submit" />
Result:
<asp:Label ID="TestResultLabel" runat="server" />
<script type="text/javascript">
generate();
</script>
When the user clicks the "submit" button, the form will post with all of the dynamic textboxes included - I chose 10 for sanity...
Here is what the code looks like to go through the form collection on the code-behind:
using System;
using System.Web;
using System.Text;
namespace StackOverflow.Web.LoopThroughForm
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
GetFormElements();
}
}
private void GetFormElements()
{
// HttpContext object contains information of the current request,
// and the Form object contains all of the submitted form elements
var form = HttpContext.Current.Request.Form;
StringBuilder sb = new StringBuilder();
string resultFormat = "<div>Element: {0} - Value: {1}";
for (int i = 0; i < form.Count; i++)
{
sb.AppendFormat(resultFormat, form.Keys[i], form[i]);
}
TestResultLabel.Text = sb.ToString();
}
}
}
This will include ALL form fields, including the ViewState field;
From here you have many options, you can hardcode the "Intrebare[]" field and only get that one, and split the result by a comma:
private void GetIntrebare()
{
var form = HttpContext.Current.Request.Form;
StringBuilder sb = new StringBuilder();
sb.Append("<div>Intrebare Values: <br />");
for (int i = 0; i < form.Count; i++)
{
if (form.Keys[i] == "intrebare[]")
{
string valuesFormat = "Value {0} : {1} <br />";
string[] values = form[i].Split(',');
for (int ii = 0; ii < values.Length; ii++)
{
// Label the value index + 1 to match the 'actual' dynamic textbox
sb.AppendFormat(valuesFormat, ii + 1, values[ii]);
}
}
}
sb.Append("</div>");
TestResultLabel.Text = sb.ToString();
}
I hope this helps to get you going with retrieving values form form/post data. FWIW, I believe MVC is the same - Controllers should also have the HttpContext object available that will contain all of this data, because under the hood, HTTP POST/GET does not care if you are using Java, .net, MVC, or whatever in order to read the values submitted by a user.
when you render your input fields give a certain class to those for example question this will also give you the advantage to style all of them at once but most important you can then use JQuery to get all and only the controls with that class question assigned.
see her for the JQuery class selector example:
http://api.jquery.com/class-selector/
if you then want to get these controls server side via C# I imagine the FindControl of web forms would not work since these controls are not server controls but simple html ones. I would try to use the HTML Agility Pack to parse the page, but at postback you should make sure the controls are created again and their values are preserved.
Personally I would loop client side using the JQuery approach and send server side the values using an Ajax PageMethod or similar approach.
Related
I have the following select list:
<select name="Context" id="Context" size="5">
<option>Context1</option>
<option>Context2</option>
<option>Context3</option>
<option>Context4</option>
<option>Context5</option>
</select>
I am using javascript to move the items of this select list up and down (this is working). I would like to feed the resulting order back to ASP.net using C#.
If I use the following line of code I get only the selected item, how do I get the whole list?
string items = Request.Form["Context"];
You can get all items like this.
var ddlArray= new Array();
var ddl = document.getElementById('Context');
for (i = 0; i < ddl.options.length; i++) {
ddlArray[i] = ddl .options[i].value;
}
Now pass this JavaScript array to your code behind.
One answer is to modify the select to make it a ListBox and then access it programattically on the server:
<asp:ListBox runat="server" name="lstContext" id="lstContext" size="5">
<asp:ListItem>Context1</asp:ListItem>
<asp:ListItem>Context2</asp:ListItem>
<asp:ListItem>Context3</asp:ListItem>
<asp:ListItem>Context4</asp:ListItem>
<asp:ListItem>Context5</asp:ListItem>
</asp:ListBox>
Note that I renamed it lstContext as calling it Context will cause build failures (due to sharing a name with the existing Context object).
Then in your code, to access the values in the order they appear:
for (int i = 0; i < lstContext.Items.Count; i++)
{
string item = lstContext.Items[i].Value;
// Do something with it
}
Your javascript should still work on the ListBox as it does for the select, so this should remain unaffected.
create a hidden field (runat=server) and store the shuffled <options> into the hidden field; You can access content of hidden field at server side by string itemsOrderedChanged = Request.Form[<HiddenFieldId>];
try to pass JavaScript value to hidden field like this .
var hidden=document.getElementById('hidValue');
var string strValues="";
for(var i=0i<ddlArray.Length;i++){
strValues+=ddlArray[i]+",";
}
hidden.value=strValues;
And in page_load or what_ever event get this string and split it.
protected HtmlControls.HtmlInputHidden hidValue;
protected void Page_Load(object sender, System.EventArgs e)
{
dynamic hiddenValue = hidValue.Value;
string [] arr=hiddenValue.Split(",");
}
// this function create mutiple htmlcontrol with id fileid1,fileid2, fileid3 etc "content_data" is a html div id.
protected void enter_rec_btn_Click(object sender, EventArgs e)
{
String control_data="";
for (Int64 x = 1; x <= 4; x++)
{
control_data = control_data + "<input type='text' id='fileid" + x + "' runat='server' /> ";
}
content_data.InnerHtml = control_data;
}
//now in another btn click just access the controls
for(Int64 i=1;i<=4;i++)
{
HtmlInputText text1,
text1 = (System.Web.UI.HtmlControls.HtmlInputText)Page.FindControl("fileid" + i);
Response.write(text1.value);
}
but it can't find the control.i already include using System.Web.UI.HtmlControls.
Help me..
thanks in advance
You are rendering a string in the Div and not actually adding the control to the web-page so find control will not work you may have to read the html of the Div you are writing to to get the controls.
Alternatively add an actual control to the page to be able to use findcontrol.
i.e MyPannel.controls.add(new ctrl.....
Good Example found here :)
http://learning2code.net/Learn/2009/8/12/Adding-Controls-to-an-ASPNET-form-Dynamically.aspx
First off, I've seen a ton of posts for this same question but what I don't understand is when somebody gives an answer about "recreating the controls to page init" or ... I have the code to dynamically CREATE the text boxes but I'm not sure what else I need to add. I don't completely understand the page life cycle of asp.net web apps. I've googled this and I dont know if I'm incompetent or if all of the answers given are for people with more understanding than me.
PLEASE provide an example of what you explain.
Basically The user enteres a # into the textbox for how many "favorite books" they want to save into the database, he/she clicks the generate button.
that # of rows will populate with two textboxes, one for title and one for author. Then I would have a button they click that would save the textbox values into the database.
I know it's a simple exercise but I'm new to asp.net and it's just an exercise I came up by myself that I'm trying to learn. I'm open to new design for this but the one thing I prefer not to do is create the textboxes statically. Thanks! <3
this is the asp.net code I have
<form id="form1" runat="server">
<div>
How many favorite books do you have ?
<asp:TextBox ID="TextBox1" runat="server" Width="50px"></asp:TextBox>
<br />
<asp:Button ID="btnBookQty" runat="server" Text="GenerateBooks" OnClick="btnBookQty_Click" />
<br />
<br />
<asp:Panel ID="pnlBooks" runat="server"></asp:Panel>
</div>
</form>
and my c# code is
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class databasetest_panels_favBookWebsite : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btnBookQty_Click(object sender, EventArgs e)
{
int count = Convert.ToInt32(TextBox1.Text);
for (int i = 1; i <= count; i++)
{
TextBox tb = new TextBox();
TextBox tb2 = new TextBox();
tb.Text = "Book " + i.ToString() + " Title";
tb2.Text = "Book " + i.ToString() + " Author";
tb.ID = "TextBoxTitle" + i.ToString();
tb2.ID = "TextBoxAuthor" + i.ToString();
pnlBooks.Controls.Add(tb);
pnlBooks.Controls.Add(tb2);
pnlBooks.Controls.Add(new LiteralControl("<br />"));
}
}
}
You don't really need to keep track of your programmatically or dynamically added controls. It's true that somehow someone has to keep track of them, but it's not you who should be doing so.
Understanding the Page Life-cycle in ASP.NET Web Forms is a must for any ASP.NET developer. Sooner or later you'll run into this sort of problems that would be greatly simplified if you really understood the underlying mechanics of the page.
Each time a request is made to the server, the whole page must be assembled from scratch. You can read (please do) on the web the many steps or stages that make up the Page Life-cycle for an ASP.NET page, but for you to have a rough idea on how this works:
When the request is made, the .aspx file is parsed and a memory source code created from it. This stage is known as the Instantiation stage, and the page's control hierarchy is created at this point.
After that, page goes through the Initialization phase, in which the page's Init event is fired. This is "the place" to add controls dynamically.
LoadViewState phase comes next. At this point, the information of the controls that are part of the page's control hierarchy get their "state" updated to make them return to the state they were before the postback. (This stage doesn't happen on the first time the page is accessed, it's a postback-only stage).
LoadPostData phase is when the data that has been posted to the server (by submitting the form) is loaded into controls. This stage is barely known to beginner ASP.NET developers, because they assume that all "state preservation" that is automatically enforced by ASP.NET engine comes from the magical Viewstate.
NOTE: If you are really serious about this, you can learn A LOT from this guy here: Understanding ASP.NET View State
What you need to remember from all the above now is that: in order for your dynamically generated controls to "have" their data "glued" together into the control's state after submitting the form by clicking this button Then I would have a button they click that would save the textbox values into the database., you need to add the controls to the page at each round-trip to the server.
The recommended way of doing so is in the Page_Init, because it comes before the LoadViewsate and LoadPostData stages where the control's state is populated.
In your case though, you don't know how many controls to add until the user fills that information on the first form submission. So, you need to find a way to add the controls to the page each time the page loads after the user entered the number of desired controls.
NOTE: You could get away with adding the controls on the btnBookQty_Click and have their data preserved correctly, because ASP.NET "plays catch-up" on the controls, but that's beyond the scope and purpose of this answer.
Add a private field to act as a boolean flag and to indicate the number of controls to add.
Create a private method that add the controls into the page, taking as argument the number of controls to add.
Call that method from within the Page_Init event handler, only if the flag dictates that some fields must be added.
In btnBookQty's click event handler set the flag to the number provided by the user of the page, and...
Call the method to create the dynamically generated controls from within btnBookQty_Click.
Here's a template code of what you need. Notice how HowManyControls property is stored in the Session to "remember" that value across postbacks:
private int HowManyControls {
get
{
if (Session["HowManyControls"] == null) return 0;
else return (int)Session["HowManyControls"];
}
set
{
Session["HowManyControls"] = value;
}
}
protected void Page_Init(object sender, EventArgs e)
{
if (Page.Ispostback && HowManyControls > 0)
{
//generate the controls dynamically
GenerateControls(HowManyControls);
}
}
protected void btnBookQty_Click(object sender, EventArgs e)
{
//get the number of controls to generate dynamically from the user posted values
HowManyControls = Convert.ToInt32(TextBox1.Text);
//generate the controls dynamically
GenerateControls(HowManyControls);
}
protected void btnSaveToDatabase_Click(object sender, EventArgs e)
{
//iterate on the control's collection in pnlBook object.
for (int i = 1; i <= HowManyControls; i++)
{
//save those value to database accessing to the control's properties as you'd regularly do:
TextBox tb = (TextBox)pnlBooks.FindControl("TextBoxTitle" + i.ToString());
TextBox tb2 = (TextBox)pnlBooks.FindControl("TextBoxAuthor" + i.ToString();
//store these values:
tb.Text;
tb2.Text;
}
}
private void GenerateControls(int count)
{
if (count == 0) { return; }
for (int i = 1; i <= count; i++)
{
TextBox tb = new TextBox();
TextBox tb2 = new TextBox();
tb.Text = "Book " + i.ToString() + " Title";
tb2.Text = "Book " + i.ToString() + " Author";
tb.ID = "TextBoxTitle" + i.ToString();
tb2.ID = "TextBoxAuthor" + i.ToString();
pnlBooks.Controls.Add(tb);
pnlBooks.Controls.Add(tb2);
pnlBooks.Controls.Add(new LiteralControl("<br />"));
}
}
EDIT
I had forgotten that ViewState is not available during Page_Init. I've now modified the answer to use Session instead.
When somebody says that "You need to keep track of the controls you create or recreate them" it means that you need to store them between postbacks.
In ASP.NET persistance can means Session variables, ViewStates and other means
See this link http://msdn.microsoft.com/en-us/magazine/cc300437.aspx
Create a list of the textboxes that you created and store it on a Session
private void CreateOrLoadTextBoxes(int numTextBoxes)
{
List<TextBox> lstControls ;
//if its the first time the controls need to be created
if(Session["lstTitleControls"] == null)
{
lstTbTitles = new List<TextBox>(numTextBoxes) ;
lstTbAuthors = new List<TextBox>(numTextBoxes) ;
//create the controls for Book Titles
for (int i = 1; i <= numTextBoxes; i++)
{
TextBox tb = new TextBox();
tb.Text = "Book " + i.ToString() + " Title";
tb.ID = "TextBoxTitle" + i.ToString();
lstTbTitles.Add(tb) ;
}
//Create the controls for Author
for (int i = 1; i <= numTextBoxes; i++)
{
TextBox tb2 = new TextBox();
tb2.Text = "Book " + i.ToString() + " Author";
tb2.ID = "TextBoxAuthor" + i.ToString();
lstTbAuthors.Add(tb2) ;
}
//store the created controls on ViewState asociated with the key "lstTitleControls" and "lstAuthorControls"
// each time you store or access a ViewState you a serialization or deserialization happens which is expensive/heavy
Session["lstTitleControls"] = lstTbTitles ;
Session["lstAuthorControls"] = lstTbAuthors ;
}
else
{
//restore the list of controls from the ViewState using the same key
lstTbTitles = (List<TextBox>) Session["lstTitleControls"];
lstTbAuthors = (List<TextBox>) Session["lstAuthorControls"];
numTextBoxes = lstTbTitles.Count() ;
}
//at this moment lstTbTitles and lstTbAuthors has a list of the controls that were just created or recovered from the ViewState
//now add the controls to the page
for (int i = 1; i <= numTextBoxes; i++)
{
pnlBooks.Controls.Add(lstTbTitles[i]);
pnlBooks.Controls.Add(lstTbAuthors[i]);
pnlBooks.Controls.Add(new LiteralControl("<br />"));
}
}
protected void Page_Load(object sender, EventArgs e)
{
CreateOrLoadTextBoxes(10) ;
}
As you have noticed I am calling the CreateOrLoadTextBoxes with a fixed value of 10
Is up to you to chane this code to take the value from the text box and call this as needed
I have this code:
var myArray = new Array();
var counter = 0;
function addElementToForm(value){
counter ++;
if (counter < 10)
{
$("#cheese").append(value + '<input type="number" value="0"><br />');
myArray.push(counter + value);
}
};
I have an ASP.NET form on the same page, in the same action of the sumbit button for the form, I want to be able to access myArray from the codefile as well!!
Take a hidden control and make it as runat="server" and try to keep the array value in the hidden control and access it from the codebehind file.
Say my WebBrowser1 downloaded a page that has a following line:
<span customattr="hamolulu">hamolulu</span>
It is inside of a td tag, inside of big table, inside of iFrame, inside of div etc.
How to I click this thing using c# ?
I need to do something following:
int i = 0;
for (i = 0; i <= 500; i++)
{
if (webBrowser1.Document.GetElementsByTagName("span")[i].GetAttribute("customattr") == "hamolulu")
{
webBrowser1.Document.GetElementsByTagName("span")[i].InvokeMember("click");
break;
}//end if
}// end for
but for some reason it does not work this way, so I'm thinking if it's possible to check the innerHTML of the span, or innerText?
I tried both:
webBrowser1.Document.GetElementsByTagName("span").InnerHTML == "hamolulu"
webBrowser1.Document.GetElementsByTagName("span").InnerText == "hamolulu"
And I failed both times.
Update:
I just noticed that the line is actually like this:
<span customattr="hamolulu"><a>hamolulu</a></span>
So I wrote a simple function:
int i = 0;
for (i = 0; i <= webBrowser1.Document.GetElementsByTagName("a").Count - 1; i++)
{
log(i.ToString()+ " : " +webBrowser1.Document.GetElementsByTagName("a")[i].InnerHtml);
} //log(string) is a custom function that saves all strings to a file log.txt
And what I've seen is that this link (and span) does not show up in my log.
In other words, getElementsByTagName("span") and getElementsByTagName("a") doesn't see the item. My guess is that it is because of iFrame. Do you have any thoughts about this?
another solution using no js (because you don't own the "page")
since it is inside an iframe then you should search within that iframe
HtmlElementCollection iframes = WebBrowser1.Document.GetElementsByTagName("iframe");
HtmlElement iframe = iframes(0 /* iframe index */); //
HtmlElementCollection spans = iframe.Document.GetElementsByTagName("span");
for (i = 0; i < spans.Count; i++) {
HtmlElement span = spans(i);
if (span.GetAttribute("customAttr") == "customAttrValue") {
string onclick = span.Children(0).GetAttribute("onclick"); //span.Children(0) should return the <a>
WebBrowser1.Document.InvokeScript(onclick);
}
}
Unless I am missing something...
<span id="hamolulu">hamolulu</span>
Then when you want to change it...
document.getElementById('hamolulu').innerHTML="<h1>Test!</h1>";
If you set up your span as an HTML server control:
<span runat="server" id="myspan" customattribute="customvalue">hello world</span>
Then you can register an event handler on page load:
protected void Page_Load(object sender, EventArgs e)
{
myspan.Attributes["onclick"] = "this.innerText='hamolulu'";
}
Another way to do it is using Page Methods which would call a page C# method using AJAX.
you can make it simpler by using JavaScript and invoking it from c# whenever you need to.
WebBrowser1 .Document .InvokeScript ("functionName")
javascript:
function functionName(){
var spans = document.getElementsByTagName('SPAN');
for (i = 0; i < spans.length; i++)
{
var span = spans[i];
if (span.getAttribute("customattr") == "hamolulu")
{
eval(span.getAttribute('onclick')); // .. be careful "span" has no "click()" method. you should use the onlick attribute if available
break;
}//end if
}// end for
}