Scenario
Inside a ContentPlaceHolder
(ContentPlaceHolder1
) of a child web page, I place the following controls:
- A
GridView
control (GridView1
) to show data rows from the Categories table of the Northwind database. - An
SqlDataSource
(SqlDataSource1
) to fetch the data from the database and bind them to the GridView
. - A
LinkButton
(LinkButton1
) to allow users to insert new data rows to the Categories table. - A
Panel
(Panel1
) and a ModalPopupExtender
(ModalPopupExtender1
) control to provide the interface for inserting new data into the database table. The value of the PopupControlID
property of the ModalPopupExtender
is set to Panel1
. This will cause the Panel1
panel to popup on the screen. - Finally, the
GridView
is wrapped inside an UpdatePanel
(UpdatePanel1
).
Each time a new data row is inserted into the database, we want to refresh the GridView
data in a smooth, AJAX way without refreshing the whole web page. How can this be done? Read on to find out.
Solution
In order to add a new data row, the user clicks the LinkButton
. Since the LinkButton
is the value of the TargetControlID
property of the ModalPopupExtender
, clicking LinkButton1
effectively causes the Panel1
panel to popup on the screen.
Panel1
contains the appropriate data entry textboxes, the OK button (OkButton
), and the Cancel button (CancelButton
). Both these buttons are connected to the ModalPopupExtender
through the OkControlID
and the CancelControlID
properties. Furthermore, the OnOkScript="onOkClick()"
property declaration causes the execution of the onOkClick()
JavaScript function when the user clicks the OkButton
button.
The onOkClick()
JavaScript function executes on the client side. It gathers user input and makes an asynchronous call to the DB.AddCategory
web (and script) method of the DB web service. DB.AddCategory
inserts a new data row into the database. Since this is an asynchronous call, success (onAddSuccess
) and failure (onAddFailure
) callback functions are defined, too.
Pay attention to the _doPostBack
call of the onAddSuccess
callback function. This is the code required in order to invoke a server postback of the OkButton
control. Note, that since we are in a ContentPlaceHolder
, the ID of the OkButton
would be something like "ctl00ContentPlaceHolder01OkButton
", and this is something that the JavaScript code must be aware of.
At this point, the server side code of the OkButton_Click
method is executed. All it does it to cause the databound GridView
to rebind itself to the SqlDataSource
. Normally, this will cause the whole web page to refresh in the browser, which is undesirable. What we really want is to refresh the GridView
without the page refresh effect. This is why I placed the GridView
inside the UpdatePanel
control.
The big question
The big question now is how we can cause the UpdatePanel
to update as soon as the new data row has been inserted into the database. To cut a long story short, all we have to do is set the correct trigger. But, which control is it going to be?
And the big answer
If you think that the LinkButton
should be the trigger, then you are like me, and unfortunately, you are wrong. The answer is that the OkButton
control inside Panel1
must be the trigger to update the UpdatePanel
. This is why we invoke a postback on OkButton
as soon as the asynchronous Web Service call has finished. The postback causes the trigger to fire, and voila! The UpdatePanel
along with the GridView
are updated (the new data row appears as a grid row). Setting the trigger is quite easy:
<Triggers>
<ajax:AsyncPostBackTrigger ControlID="OkButton" EventName="Click" />
</Triggers>
Last but not least, make sure that you set the UpdateMode
property of the UpdatePanel
to "Conditional". Also, do not forget to make the DB Web Service available to the JavaScript code:
<ajax:ScriptManager ID="ScriptManager1" runat="server">
<Services>
<ajax:ServiceReference Path="DB.asmx" />
</Services>
</ajax:ScriptManager>
To recap, what you must keep in mind is the following series of events:
(1) The user clicks the LinkButton
-> (2) The ModalPopupExtender
pops up Panel1
. The user enters data and clicks the OK button -> (3) The onOkClick()
JavaScript code is executed. An asynchronous Web Service call is made, and a new data row is inserted into the database. Upon success, the control returns to the onAddSuccess
callback function which -> (4) fires a postback to invoke the server side code of the OK button -> (5) Since the OK button is the trigger of the UpdatePanel
, the postback effectively causes the UpdatePanel
and its contents to update.
Points of interest
- MasterPages are everywhere. In this scenario, all controls are placed inside a
ContentPlaceHolder
of a child page. This alone brings the effect of modified control IDs. You must be careful if you want to invoke control postbacks from JavaScript client code. - After having inserted a data row to the database, the databound
GridView
must be refreshed. Since the GridView
is inside an UpdatePanel
, this equals to updating the UpdatePanel
. You can only achieve this by placing the appropriate trigger. In this scenario, this can prove to be unobvious at first.
Why I wrote this
It took me one week to solve this out. Googling the Internet only helped me with bits and pieces. It seemed like I couldn't find a straightforward and complete answer anywhere. That is why I decided to contribute this to the community. Asking is too easy, but providing solutions can be hard.