Passing column value from specific row index of a GridView - asp.net

Suppose I have a gridview containing some bound fields and a template field. The template field contains a button (btnUpload).
btnUpload triggers a modalpopupextender to display a panel which contains some controls and a submit button.
What I need to be able to do is to get the value from cell 0 of the row btnUpload was clicked on and pass it to the panel so I can retrieve some data into the panel's controls in the panel_load event based on that value from cell 0 of the gridview.
I thought I could do this by storing the value from cell 0 in a session variable but not sure if this is the 'best' way of doing this?
UPDATE - Using hidden fields on the panel to store row index as suggested by Karl
I have added two hidden fields to the panel and I populate them as below:
If e.CommandName = "Upload" Then
Dim row As GridViewRow = CType(CType(e.CommandSource, Control).NamingContainer, GridViewRow)
Dim ref As String = CType(row.Cells(0), DataControlFieldCell).Text
Dim dt As String = CType(row.Cells(2), DataControlFieldCell).Text
hfRef.Value = ref
hfDate.Value = dt
End If
This is working and populating the hidden fields OK. However in the btnSubmit_Click event procedure on the panel I am doing the following the variables I am assigning are not getting a value from the hidden fields:
If fuCertificate.HasFile Then
Dim fileName As String = Path.GetFileName(fuCertificate.PostedFile.FileName)
fuCertificate.SaveAs(Server.MapPath("~/CalibrationCerts/" & fileName))
Dim ref As String = hfRef.Value
Dim dt As String = hfDate.Value
Dim dc As New ExternalCalibrationDataContext
Dim thisRecord = (From x In dc.ext_calibration_records
Where x.calibration_no = ref AndAlso
x.calibration_date = dt).ToList()(0)
thisRecord.certificate_no = txtCertNumber.Text
thisRecord.certificate = "~/CalibrationCerts/" & fileName
Else
lblError.Text = "Please select a file to upload"
End If

I would recommend putting a HiddenField control in the panel used by the ModalPopupExtender. It will be easier to work with the HiddenField control than Session, because you will not need to do the casting of the hidden field Value to a string, because it already is a string. All Session objects are stored as Object, so it is necessary to cast to a string when retrieving the value from Session.
Hidden field option:
<asp:Panel>
// Other stuff for your modal popup
<asp:HiddenField id="HiddenField1` runat="server" />
</asp:Panel>
// Set hidden field
HiddenField1.Value = cell0.Text
// Get hidden field
string theValue = HiddenField1.Value
Session option:
// Set the value in Session
Session["Cell0Text"] = cell0.Text
// Retrieve the value from Session
// First check to see if the Session value still exists
if(Session["Cell0Text"] != null)
{
// Now cast the Session object to a string
string theValue = Session["Cell0Text"].ToString()
}

Related

ASP.NET Accessing control with dynamically generated IDs

I have a form which contains a repeater with a HiddenField control within whose IDs are dynamically created.
Dim tNewOrder As HiddenField = CType(e.Item.FindControl("tNewOrder"), HiddenField)
tNewOrder.ID = "tNewOrder" & CategoryId
When I submit the form i'm looping through the repeater and trying to access each HiddenField value but i get error 'Object reference not set to an instance of an object.'
For Each CatItem As RepeaterItem In reCategory.Items
Dim hCategoryId As HiddenField = CType(CatItem.FindControl("hCategoryId"), HiddenField)
Dim tNewOrder As HiddenField = CType(CatItem.FindControl("tNewOrder" & hCategoryId.Value), HiddenField)
Response.Write(tNewOrder.Value)
Next
Is there a way to find controls with dynamically generated IDs?
I've found a way around the issue so thought i'd post it here.
Instead of dynamically creating the control IDs I set ID to 'tNewOrder' and the ClientIDMode:
change this line:
tNewOrder.ID = "tNewOrder" & CategoryId
to:
tNewOrder.ClientIDMode = UI.ClientIDMode.Predictable
I then knew the IDs would be generated as tNewOrder_0, tNewOrder_1, tNewOrder_2 per repeater index.
So I could then access the values by:
For Each CatItem As RepeaterItem In reCategory.Items
Dim tNewOrder As HiddenField = CType(CatItem.FindControl("tNewOrder"), HiddenField)
Response.Write(tNewOrder.Value)
Next

ORA-01036: illegal variable name/number error on parameter in SELECT

I am trying to populate a series of dropdown lists in a GridView. In the RowDataBound event, I call based on other info in the gridviewrow to get the items for populating dropdowns in the row. I am getting "ORA-01036: illegal variable name/number error on parameter" on the following code.
Dim rowTemp As GridViewRow = ddlItemDesc.Parent.Parent
Dim lblYear As Label = rowTemp.FindControl("lblSchoolYear")
Dim strYear As String = lblYear.Text.Trim()
Dim strSelect As String = "SELECT FOO.BAR.PRODUCT_CODE || ' :: ' || FOO.BAR.PRODUCT_DESC AS txt, FOO.BAR.PRODUCT_KEY AS val, :currentYear AS CURRENT_YEAR FROM FOO.BAR WHERE (FOO.BAR.PRODUCT_KEY=:itemKey)"
Dim daTemp As New OracleDataAdapter(strSelect, oConn)
daTemp.SelectCommand.Parameters.Add("currentYear", CDate(strYear))
daTemp.SelectCommand.Parameters.Add("itemKey", strItemVal(0))
Dim dtProd As New DataTable
daTemp.Fill(dtProd)
If I remove ":currentYear AS CURRENT_YEAR" from the SELECT statement, it runs fine. I use the same statement in another SELECT from a join of other tables with no problem.
The strYear comes from a label in the gridviewrow and I have checked that it has data and that it is valid for CDate (I've also tried it simply as a string with the same results). StrItemVal(0) comes from another dropdownlist (the one that is successfully populated using :currentYear being passed in). This code only gets called if that dropdown list has a value in it that is selected.

Issue binding a DataTable to an ASP.Net GridView control

I'm trying to allow my users to enter in large lists of data using an ASP.Net GridView control. The affect I'm trying to create is to make the GridView control act like a spreadsheet. The user can freely enter data and tab from column to column and row to row. The user can use a button at the bottom of the page to add rows as needed. There is also a button at the bottom of the form to save as needed.
To do this, I created a DataTable with a bunch of empty rows and bound it to a GridView. The GridView's columns are template columns that contain textboxes. So, when the page opens, it actually looks like a spread sheet. When the user hits the add rows button, I just add another ten rows to the DataTable the GridView is bound to and it works like a charm.
The issue I'm running into is reading the data that the user entered. When the user hits the paging link or the update button, I would like to update the DataTable with the data the user typed in. Here is what I have.
Private Sub UpdateDataTable()
Dim objCatRow As clsCategoriesRow = Session("gvCategoriesRow")
Dim drQuery() As DataRow = Nothing
Dim drRow As DataRow = Nothing
Dim objRow As GridViewRow = Nothing
Dim intRecNo As Integer = 0
Dim txt As TextBox = Nothing
Dim lbl As Label = Nothing
'Loop through all of the rows in the grid view control
For Each objRow In Me.gvCategories.Rows
'Get the label that contains the identity column
lbl = objRow.Cells(GridColumns.Category).FindControl("lblItemRecNo")
intRecNo = lbl.Text
'Update the datarow bound to this grid view row
'First, query the datarow from the data table
drQuery = objCatRow.Table.Select("recno = " & intRecNo)
'Make sure our query returned a row
If Not IsNothing(drQuery) AndAlso drQuery.Count > 0 Then
'Get the value from the textbox in the grid view
txt = objRow.Cells(GridColumns.Category).FindControl("txtItemCategory")
'Upadte the data row with the value the user entered
'THE VALUE IN txt.Text IS EMPTY. HOW CAN I GET THE VALUE THE USER TYPED IN?
drQuery(0)("Category") = txt.Text
'Get the value from the textbox in the grid view
txt = objRow.Cells(GridColumns.SortORder).FindControl("txtItemSortOrder")
'Upadte the data row with the value the user entered
drQuery(0)("sortorder") = txt.Text
End If
Next
End Sub
The issue is that this is not returning what the user typed in. The line
txt = objRow.Cells(GridColumns.Category).FindControl("txtItemCategory")
returns a reference to the textbox in the templated column. But, it contains the previous value, the value from the view state, not the value the user typed in.
How can I get the value the user typed into the grid?
I want to mention that I know how to add EDIT and UPDATE buttons to each row. I would like to avoid doing that way if I can. My users have huge lists of data to enter in and that approach would make the application unusable.
Thanks in advance,
Mike
The form data posted by the user is found in the Page.Request.Form.Item collection. The Page.Request.Form.AllKeys lists the "keys" associated with all of the form item values.
If Page.Request.Form.HasKeys Then
For Each key as String In Page.Request.Form.AllKeys
' step through the keys and use Page.Request.Form.Item(key) to get the data entered
Next
end If
After testing, I was able to get the data from the Request.Form data or the GridView control during page.load on postback, as long as you don't bind the control on postback, but only during the initial request ("GET").
Keep in mind, controls have to be re-created for each request to the page. The Request data posted is used by ASP.NET to repopulate form data controls only after the controls are re-created on the page and the ViewState for the controls is processed, etc.
Request.Form collection
ASP.NET Page Life Cycle
You should replace this:
txt = objRow.Cells(GridColumns.Category).FindControl("txtItemCategory")
with this
txt = objRow.Cells(GridColumns.Category).FindControl("txtItemCategory").Value

Programatically created ASP.NET TextBox retains Text value after PostBack even if Control is cleared

I have a drop down menu, and based on which item is selected, I call a web service and then dynamically create some text boxes.
The first time I drop down the menu and select an item, it works perfectly, and the text boxes are created and populated dynamically. However, the next time I drop down the menu (after the first postback), and select something different... after the second postback, the original values remain in the textboxes.
I am clearing all of the text boxes out of the placeholder, then re-creating them, and then setting a NEW value, how can they retain the OLD values... especially if I controls.clear them from the page?
Note: The second time they are being created, the textbox IDs DO end up being the same. Could that have something to do with it? This duplicate ID functionality will need to be supported.
My code, called from Page_Load, is as follows: (edited to add more code)
Private Sub RefreshEntity()
Dim XmlRecords As New XmlDocument
Dim XmlRecordsNode As XmlNode
Dim EntityType As String = EntityTypes.SelectedValue
Dim Entity As String = RecordValue.Value
Dim FieldName As String
Dim FieldValue As String
FieldPlaceHolder.Controls.Clear()
If RecordList.SelectedValue <> "Select..." Then
Try
XmlRecordsNode = LoginInfo.SharePointConnectWebService.GetMetaData(LoginInfo.WSUser, LoginInfo.WSPass, _
EntityType, Entity)
XmlRecords.LoadXml(XmlRecordsNode.OuterXml)
Catch ex As Exception
ConfirmLabel.Text = "<b>Error:</b><br>" & ex.Message.ToString
Return
End Try
Else
SetProperties.Visible = False
Return
End If
For Each OneNode As XmlNode In XmlRecords.SelectNodes("Fields").Item(0).ChildNodes
FieldName = OneNode.Name
FieldValue = OneNode.InnerText
Dim newLabel As Label = New Label()
newLabel.Text = FieldName & ": "
Dim newTextBox As TextBox = New TextBox()
newTextBox.ID = "Field-" & FieldName
newTextBox.Text = FieldValue
Dim newLine As Label = New Label()
newLine.Text = "<br><br>"
FieldPlaceHolder.Controls.Add(newLabel)
FieldPlaceHolder.Controls.Add(newTextBox)
FieldPlaceHolder.Controls.Add(newLine)
Next
SetProperties.Visible = True
End Sub
And the RecordValue.Value is a hidden field that gets populated in every Page_Load:
RecordValue.Value = RecordList.SelectedValue
Where RecordList is my DropDown menu.
This is likely due to ViewState or the Posted values clobbering your values.
Once a control is dynamically added to the controls collection it needs to catch up with all the page life cycle events that have already fired. In the case of a post back this means that the ViewState and/or the posted form value will clobber the .text property on the TextBox based on the order you're adding the dynamic controls to the controls collection and setting the .text property.
To fix this you can disable ViewState by setting the .EnableViewState property to false on the dynamically generate controls also add the controls to the controls collection before you set any properties on them.
For Each OneNode As XmlNode In XmlRecords.SelectNodes("Fields").Item(0).ChildNodes
FieldName = OneNode.Name
FieldValue = OneNode.InnerText
Dim newLabel As Label = New Label()
Dim newTextBox As TextBox = New TextBox()
Dim newLine As Label = New Label()
newTextBox.ID = "Field-" & FieldName
newLabel.EnableViewState = False
newTextBox.EnableViewState = False
newLine.EnableViewState = False
FieldPlaceHolder.Controls.Add(newLabel)
FieldPlaceHolder.Controls.Add(newTextBox)
FieldPlaceHolder.Controls.Add(newLine)
newLabel.Text = FieldName & ": "
newTextBox.Text = FieldValue
newLine.Text = "<br><br>"
Next
You're not storing the value in a Session variable and then putting it back into the text box later in your code?

RangeValidator not working when selecting DropDownList value using jQuery

I inherited a site which I am in the middle of updating which has a DropDownList and a RangeValidator assigned to it. The data is bound to the dropdown on Page_Load. The values are retrieved from the database so the value property of each item is set to the unique ID of the item in the DB.
The RangeValidator looks something like:
<asp:rangevalidator id="ddRangeValidator" runat="server" ControlToValidate="ddMenu" ErrorMessage="Please select value in range" MinimumValue="1" MaximumValue="100000" Type="Integer">*</asp:rangevalidator>
I have a method which automatically populates this value in jQuery e.g.
$("#ddMenu").val("An Option");
This works, however, when I try to post the page the range validation fails. Then even if I manually select that value, or select another valid value it still won't validate. The only way to make it validate is to select non-valid value and then re-selecting a valid one.
Any ideas?
Update
Here is the data binding code:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load, Me.Load
If Not Page.IsPostBack Then
Dim ds As New DataSet()
Dim myDbObject As New myDbObject()
ds = myDbObject.ToDataSet() // retrieves all objects from the database
// store the results in a temporary view to filter
Dim dv As DataView
dv = New DataView(ds.Tables(0), "IsLive = True", "ID", DataViewRowState.CurrentRows)
Dim i As Integer = 0
ddMenu.Items.Add("Select a value")
ddMenu.Items.Item(0).Value = 0
// add all objects from filtered list into drop down menu
For i = 0 To dv.Count - 1
With ddMenu.Items
// add a new item
.Add(dv.Item(i).Item("Name"))
// set the Value property as unique ID of object
.Item(i + 1).Value = dv.Item(i).Item("ID")
End With
Next
End If
End If
Turns out it was an issue with my page loading twice...so now the issue is going to be tracking down why it is loading twice!
I guess the Range validator verifies the actual "value" of the dropdown list. May it be possible that by using jQuery to populate your dropdown the actual entry doesn't get a proper option "value"? Could you maybe post the rendered HTML code of your dropdown list?

Resources