3

Here is the scenario.

I have a simple page containing an asp:PlaceHolder.

<%@ Page Title="" Language="VB" MasterPageFile="~/MasterPage.master" AutoEventWireup="false" CodeFile="TrainingPlan.aspx.vb" Inherits="TrainingPlan" %>
<%@ Reference Control="ctlTask.ascx" %>
<%@ Reference Control="ctlTaskheader.ascx" %>

<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" Runat="Server">

    <div class="centered">
        <h2><asp:Label ID="lblPlanTitle" runat="server" Text="Plan Title"></asp:Label></h2>
        <hr />
        <br />
        <asp:ImageButton ID="imgbtnSave" runat="server" ImageUrl="~/Images/save.ico" />
        <br />
        <asp:PlaceHolder ID="PlanPlaceHolder" runat="server"></asp:PlaceHolder>
    </div>
</asp:Content>

The placeholder on this page is populated with several rows of the same web user control. This web user control contains several textboxes. For each textbox in this web user control I have public properties to set and get the text value. In the page load event of the web user control I am adding onClick attributes to some of those textboxes like so.

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    txtTrainingStart.Attributes.Add("onClick", "txtTrainingStart_Click(" &  txtTrainingStart.ClientID & ", " & txtTask.ClientID & ");")
    txtTraineeBadgeNum.Attributes.Add("onClick", "txtTraineeBadgeNum_Click(" & txtTraineeBadgeNum.ClientID & ", " & txtTask.ClientID & ", " & txtTrainingStart.ClientID & ");")
    txtTrainerBadgeNum.Attributes.Add("onClick", "txtTrainerBadgeNum_Click(" & txtTrainerBadgeNum.ClientID & ", " & txtTrainingComplete.ClientID & ", " & txtTask.ClientID & ", " & txtTraineeBadgeNum.ClientID & ", " & Session.Item("isTrainer").ToString.ToLower & ");")
    txtDecertifyingOfficial.Attributes.Add("onClick", "txtDecertifyingOfficial_Click(" & txtDecertifyingOfficial.ClientID & ", " & txtTrainerBadgeNum.ClientID & ", " & txtTask.ClientID & ", " & Session.Item("isDecertifyingOfficial").ToString.ToLower & ");")
End Sub

For each of those onClick events I have corresponding javascript functions.

<script type="text/javascript">
    function txtTrainingStart_Click(txtTrainingStart, txtTask) {
        //processing and updates to textboxes here
    }
</script>

Here is the problem.

On the main page containing the placeholder I have a save button. In the click event of the save button I am looping through each of the web user controls contained in the placeholder to process and save the data.

Protected Sub imgbtnSave_Click(sender As Object, e As ImageClickEventArgs) Handles imgbtnSave.Click
    For Each item As Control In PlanPlaceHolder.Controls
        Dim task As ctlTask = TryCast(item, ctlTask)

        If Not IsNothing(task) Then
            'need updated textbox values here. 
            'The following line gets the original textbox value, not the updated value that I need
            Dim test As String = task.trainingStart

        End If
    Next
End Sub

Everything I have tried I can only get the original value that was in the textbox when the page loaded. I would think that this should be simple and I am just missing something basic. I've searched google high and low for the solution but I have yet to find one. This was the closest thing I found -> Set Text property of asp:label in Javascript PROPER way. Although that post deals with a label rather than a textbox and isn't using a placeholder containing several web user controls. From what I understand I need to POST the updates back to the server from the client but I don't know how to do this. I've tried using the Request.Form property but I couldn't seem to make that work. What am I missing?

Thank you for any help, Rylan

EDIT
Here is the code that populates the placeholder with the web user controls as requested

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    Dim DBConn As MySqlConnection
    Dim cmd As New MySqlCommand

    DBConn = New MySqlConnection(Globals.mysqlConStr)

    Try
        lblPlanTitle.Text = Request.QueryString("plan_name") & " Training Plan"

        If Session.Item("empID") = -1 Then
            empID = clsUser.getID
        Else
            empID = Session.Item("empID")
        End If

        Dim strSQL As String = "SELECT * FROM task_revs tr WHERE tr.change != 'Deleted' and tr.id_plan = " & Request.QueryString("id_plan") & " ORDER BY task_num, rev_date desc"
        Dim da As New MySqlDataAdapter(strSQL, DBConn)
        Dim dtAllRevs As New DataTable
        da.Fill(dtAllRevs)

        Dim dtCurrentRev As New DataTable
        Dim lastTaskNum As String = ""
        dtCurrentRev = dtAllRevs.Clone
        For Each row As DataRow In dtAllRevs.Rows
            If lastTaskNum <> row("task_num") Then
                dtCurrentRev.ImportRow(row)
                lastTaskNum = row("task_num")
            End If
        Next

        strSQL = "SELECT * FROM checkoffs WHERE emp_id = " & empID
        da = New MySqlDataAdapter(strSQL, DBConn)
        Dim dtCheckoffs As New DataTable
        da.Fill(dtCheckoffs)
        Dim addColor As Boolean = True
        Dim tabWidth As Integer

        Dim Header As ctlTaskHeader = LoadControl("ctlTaskHeader.ascx")
        PlanPlaceHolder.Controls.Add(Header)

        For Each row As DataRow In dtCurrentRev.Rows
            Dim newRow As ctlTask = LoadControl("ctlTask.ascx")
            tabWidth = 0

            newRow.id_Task = row("id_Task")
            newRow.taskNum = row("task_num")
            newRow.task = row("task")

            If row("is_header") = True Then
                If row("task_num").ToString.EndsWith(".0") And row("task_num").ToString.Split(".").Count = 2 Then
                    newRow.taskBold = True
                    newRow.taskItalic = True
                Else
                    newRow.taskForeColor = Drawing.Color.Blue
                    newRow.taskItalic = True
                    tabWidth += 10
                End If
            Else
                tabWidth += 10
            End If

            For i As Integer = 0 To row("task_num").ToString.Split(".").Count - 3
                tabWidth += 10
            Next
            newRow.TabSize = tabWidth

            If Not IsDBNull(row("task_level")) Then
                For i As Integer = 0 To row("task_level") - 1
                    newRow.taskLevel = newRow.taskLevel & "*"
                Next
            End If

            If addColor = True Then
                newRow.taskNumBackColor = Drawing.Color.LightGray
                newRow.taskLevelBackColor = Drawing.Color.LightGray
                newRow.taskBackColor = Drawing.Color.LightGray
                newRow.trainingStartBackColor = Drawing.Color.LightGray
                newRow.trainingCompleteBackColor = Drawing.Color.LightGray
                newRow.traineeBadgeNumBackColor = Drawing.Color.LightGray
                newRow.trainerBadgeNumBackColor = Drawing.Color.LightGray
                newRow.decertifyingOfficialBackColor = Drawing.Color.LightGray
            End If
            addColor = Not addColor

            For Each checkoff As DataRow In dtCheckoffs.Rows
                If checkoff("id_task") = row("id_task") Then
                    If Not IsDBNull(checkoff("training_start")) Then
                        newRow.trainingStart = checkoff("training_start")
                    End If
                    If Not IsDBNull(checkoff("training_complete")) Then
                        newRow.trainingComplete = checkoff("training_complete")
                    End If
                    If Not IsDBNull(checkoff("trainee_badge")) Then
                        newRow.traineeBadgeNum = checkoff("trainee_badge")
                    End If
                    If Not IsDBNull(checkoff("trainer_badge")) Then
                        newRow.trainerBadgeNum = checkoff("trainer_badge")
                    End If
                    If Not IsDBNull(checkoff("decertifying_official")) Then
                        newRow.decertifyingOfficial = checkoff("decertifying_official")
                        newRow.taskNumBackColor = Drawing.Color.LightSalmon
                        newRow.taskLevelBackColor = Drawing.Color.LightSalmon
                        newRow.taskBackColor = Drawing.Color.LightSalmon
                        newRow.trainingStartBackColor = Drawing.Color.LightSalmon
                        newRow.trainingCompleteBackColor = Drawing.Color.LightSalmon
                        newRow.traineeBadgeNumBackColor = Drawing.Color.LightSalmon
                        newRow.trainerBadgeNumBackColor = Drawing.Color.LightSalmon
                        newRow.decertifyingOfficialBackColor = Drawing.Color.LightSalmon
                    End If
                End If
            Next

            If row("is_header") = True And PlanPlaceHolder.Controls.Count > 1 Then
                Dim newLine As LiteralControl = New LiteralControl("<br/>")
                PlanPlaceHolder.Controls.Add(newLine)
            End If
            PlanPlaceHolder.Controls.Add(newRow)
        Next
    Catch ex As Exception
        clsLog.logError(ex)
    Finally
        DBConn.Close()
    End Try

EDIT 2
I thought it might also be important to show how I am making updates to the textboxes in my javascript functions

    function txtTrainingStart_Click(txtTrainingStart, txtTask) {

                var currentdate = new Date();
                var datetime = (currentdate.getMonth() + 1) + "/" + currentdate.getDate() + "/" + currentdate.getFullYear() + " " + getTimeAMPM();
                txtTrainingStart.value = datetime;
                txtTrainingStart.style.backgroundColor = "yellow";

    }
Community
  • 1
  • 1
rylan37
  • 31
  • 5
  • Have you think about passing the input values ​​for a "HiddenField" by using javascript and go as they are updated? – PiLHA Aug 06 '13 at 14:48
  • Add the code that populates the placeholder and text box values. – Michael Liu Aug 06 '13 at 14:53
  • @PilHA I have not tried this but I don't see how the field being hidden changes anything? Maybe I do not fully understand what you mean, can you elaborate? – rylan37 Aug 06 '13 at 15:11
  • @MichaelLiu I added the code used to populate the placeholder and textbox values as requested. – rylan37 Aug 06 '13 at 15:12

2 Answers2

0

Edit 3:

The below code will work for static controls, but dynamically-created controls will not be preserved on postback. You will need to store the updated values so they can be retrieved on postback somehow (e.g. a Session variable or HiddenField). If possible, I would create the controls statically and populate them in page_load, hiding controls with no data - this would allow you to get the values on postback as below.


Hmm...I set up a super simplified version of your code and ran it pretty much as is (without the database function), and it seems to be working fine.

Here is the simplified version I used:

<asp:Content id="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <asp:ImageButton ID="imgbtnSave" runat="server"></asp:ImageButton>
    <asp:PlaceHolder ID="PlanPlaceHolder" runat="server">
        <asp:TextBox runat="server" ID="txtTrainingStart" value="before" ></asp:TextBox>
    </asp:PlaceHolder>
</asp:Content>

Javascript:

function txtTrainingStart_Click(txtTrainingStart, txtTask) {

    var currentdate = new Date();
    var test = "after";
    txtTrainingStart.value = test;
    txtTrainingStart.style.backgroundColor = "yellow";
}

VB:

Protected Sub imgbtnSave_Click(ByVal sender As Object, ByVal e As ImageClickEventArgs Handles imgbtnSave.Click
    For Each item As TextBox In PlanPlaceHolder.Controls
        'need updated textbox values here.'
        Debug.WriteLine(item.ID)
        Debug.WriteLine(item.Text)
    Next
End Sub

I'm getting the updated value of the textbox, so you should be able to pass that value to a function and do whatever operations you need.

Let me know if I'm missing something.

Edit 2: I just had a thought--can you check if page_load is being called after you click the save button? I wonder if it is overwriting your updated values with the original values again.

If it is, I would wrap the database functionality in page_load with a postback check:

If Not IsPostBack
    ' connect to database'
    ' populate placeholder'
End If
lem
  • 155
  • 1
  • 11
  • 1. When I change onClick to onClientClick my click events no longer fire. 2. I tried adding `__doPostBack('imgbtnSave','');` to the end of my javascript click events and this just causes the updates I just made to be removed. 3. I tried the update panel (also had to add a scriptmanager to my masterpage) but this doesn't do anything, same results as I had before, I am unable to pull the updated values. – rylan37 Aug 07 '13 at 12:42
  • I think I misunderstood your question, so I tested some code and rewrote my answer above. – lem Aug 07 '13 at 15:35
  • You are exactly right! The save button click is causing the `page_load` event to fire again thus overwriting my values. Problem is if I intercept it using `IsPostBack` in `page_load` the original page is already gone. I think maybe I need to use an update panel. I'll see what I can figure out and post what I find. – rylan37 Aug 08 '13 at 11:58
  • Hmm...`IsPostBack` would work if you were using static controls, but it seems that dynamically-created controls are their own beast. Worst case, you might have to store your data in Session variables or use some other method to make sure the original values are preserved on postback. – lem Aug 08 '13 at 14:35
  • I would say if you have a set number of fields to create them statically and populate them in `page_load`, making them hidden if you don't want them to be seen. Did some research on dynamic controls and they seem like a lot of trouble. – lem Aug 08 '13 at 14:47
  • I edited my answer again to reflect recent research - hope it helps! – lem Aug 08 '13 at 15:28
  • You can't updated session variables from javascript as its on the client side and the session variables are on the server side. Storing the values in hidden fields wouldn't change anything either. I did however figure out the solution and posted my answer. Thank you for all the help, wouldn't have figured it out without you. – rylan37 Aug 08 '13 at 20:32
0

I have figured it out. I was on the right track using Request.Form I just didn't fully understand how to use it yet.

New code for my save button

Protected Sub imgbtnSave_Click(sender As Object, e As ImageClickEventArgs) Handles imgbtnSave.Click
    Dim coll As NameValueCollection
    coll = Request.Form

    For x = 0 To coll.Count - 1
        Response.Write("Key = " & coll.GetKey(x) & " Value = " & coll(x) & "<br />")
    Next
End Sub

The loop outputs all the control keys and updated values from the postback like so.

Key = ctl00$MainContent$ctl01$txtTrainingStart Value = 8/1/13
Key = ctl00$MainContent$ctl01$txtTrainingComplete Value = 8/2/13
Key = ctl00$MainContent$ctl02$txtTrainingStart Value = 8/3/13
Key = ctl00$MainContent$ctl02$txtTrainingComplete Value = 8/4/13

I use a hidden field to store a database row id with each dynamically created web user control. From that point it's easy to insert the updated values into my database.

rylan37
  • 31
  • 5