Home > .net 2.0, AJAX, c#, Visual Studio 2005, Visual Studio 2008 > Updated: Creating a Lookup Modal Popup

Updated: Creating a Lookup Modal Popup

August 14, 2007

The ModalPopupExtender continues to be the most diverse and absolutely fantastic part of the AJAX Control Toolkit to date.  While the other controls do “cool things,” the MPE really helps add a level of usability to applications and bridge the gaps for those users who are still a bit less grounded in web-based applications and long for the familiarity of their client/server applications.

Okay, 4 projects and several scenarios later, I’ve reworked a bit of the code I originally posted up back in June.

Some things I’ve discovered:

  • A user control isn’t totally necessary and a custom control is painful to implement due to the lack of a designer.  The more I think about it, the more a true drag/drop control would be cool… but I just can’t see it for now.  You CAN encapsulate each of these popups into user controls, but I didn’t see any real advantage to it unless you have HUGE ASPX pages and have trouble keeping the code together.
  • Session (my choice, better or worse) or ViewState is your friend due to the constant “refreshing” of the page.  If there’s a better way than using Session or ViewState, I’m still interested!
  • Paging is possible within the popup!

We’ll use the same example as the last post: looking up a student.

Lookup Student Modal Popup

Thecode is quite simple: two TextBox controls, two Button controls, and a DropDownList.  The DropDownList has the AJAX Control Toolkit’s ListSearchExtender control applied to it.  I LOVE this control (being a keyboard guy).  There’s also a GridView that is hidden until results are found (by clicking Search).

Lookup Student Modal Popup

To build the popup, our code looks pretty slim.  The ModalPopupExtender, a Panel, the UpdatePanels, and controls mentioned above.

Our ModalPopupExtender (MPE) code specifies the PopupControlId (our Panel), the button that will activate it, and the Css to format it like I have above.

<AjaxToolkit:ModalPopupExtender

ID=”StudentLookupPopupExtender”

runat=”server”

PopupControlID=”StudentLookupPanel”

TargetControlID=”AddStudentsButton”

BackgroundCssClass=”ModalBackground” />

Our Panel control specifies it’s own CSS class.

<asp:Panel

ID=”StudentLookupPanel”

runat=”server”

CssClass=”PopupPanel”>

Finally, our UpdatePanel sets the mode to Conditional to prevent other controls (just incase) from getting in the way.

<asp:UpdatePanel

ID=”StudentLookupUpdatePanel”

runat=”server”

UpdateMode=”Conditional”>

Our GridView has two events associated with it: PageIndexChanging and RowCommand.  PageIndexChanging will allow us to page through our results set and Rowcommand will be associated with our Select command we’ll use later.  Beyond that, for this example, everything is VERY standard.  Bound fields.  Very exciting, right?

<asp:GridView

ID=”StudentLookupGridView”

runat=”server”

AutoGenerateColumns=”False”

Style=”text-align: center”

AllowPaging=”True”

OnPageIndexChanging=”StudentLookupGridView_PageIndexChanging”

Width=”100%”

OnRowCommand=”StudentLookupGridView_RowCommand”>

<Columns>

<asp:ButtonField CommandName=”SelectStudent” Text=”Select” />

<asp:BoundField DataField=”StudentId” HeaderText=”Student Id” />

<asp:BoundField DataField=”FullName” HeaderText=”Student Name” />

<asp:BoundField DataField=”SchoolName” HeaderText=”School” />

<asp:BoundField DataField=”Grade” HeaderText=”Grade” />

</Columns>

</asp:GridView>

So, we have a total of four events to code against.  I’ll explain in the order that they would normally flow.

  1. The Search button’s Click
  2. The GridView’s PageIndexChanging
  3. The GridView’s RowCommand
  4. The Close button’s Click

Search Button

The Search button will do most of the heavy lifting for the entire pop-up.  It will take the entry information, go out, query the data source, and populate our GridView.  For my example, my data source is a method in our framework library.  Any SQL, Oracle, Object, or even LINQ data source would suffice.

protected void StudentLookupSearchButton_Click(object sender, EventArgs e)

{

Incident incident = (Incident)Session[“Incident”];

StudentCollection students =

Students.GetStudentCollectionByFirstOrLastName(

StudentLookupFirstNameTextBox.Text,

StudentLookupLastNameTextBox.Text,

Convert.ToInt32(StudentLookupSchoolDropDown.SelectedValue));

Session[“LookupStudentCollection”] = students;

StudentLookupGridView.DataSource = students;

StudentLookupGridView.DataBind();

foreach (GridViewRow row in StudentLookupGridView.Rows)

{

if (incident.StudentId == Convert.ToInt32(row.Cells[1].Text))

{

row.BackColor = System.Drawing.Color.LightGreen;

}

}

}

Prior code has populated the Session with an incident (a record) object.  In the event this is a repeat search, set the back color of our GridViewRows to light green (selected color).  That part is not necessary, simply a visual cue for my customers.  You might be asking: why did you add your results set to Session?  For our data paging, of course!  Why requery?

GridView’s PageIndexChanging

protected void StudentLookupGridView_PageIndexChanging(object sender, GridViewPageEventArgs e)

{

// Recapture the current StudentCollection.

StudentLookupGridView.DataSource =

(StudentCollection)Session[“LookupStudentCollection”];

// Set to the “new page”.

StudentLookupGridView.PageIndex = e.NewPageIndex;

// Rebind the data.

StudentLookupGridView.DataBind();

}

Very simplistic and textbook; though several examples show requerying the datasource… in our environment, that data source is only populated once a day.  If requerying is necessary, this is the event you’d do it in.

GridView’s RowCommand

Now we’ve found the record we’re interested in and are ready to select it.  When you click ‘Select’, the SelectStudent command fires and is caught by the GridView’s OnRowCommand event.

protected void StudentLookupGridView_RowCommand(object sender, GridViewCommandEventArgs e)

{

if (e.CommandName == “SelectStudent”)

{

Incident currentIncident =

(Incident)Session[“Incident”];

GridViewRow row =

StudentLookupGridView.Rows[Convert.ToInt32(e.CommandArgument)];

int selectedStudent =

Convert.ToInt32(row.Cells[1].Text);

if (currentIncident.StudentId == selectedStudent)

{

currentIncident.StudentId = 0;

row.BackColor = System.Drawing.Color.Empty;

}

else

{

foreach (GridViewRow viewRow in StudentLookupGridView.Rows)

{

viewRow.BackColor = System.Drawing.Color.Empty;

}

currentIncident.StudentId = selectedStudent;

row.BackColor = System.Drawing.Color.LightGreen;

}

}

}

Okay… in this event, we’re simply capturing the second cell (the student’s ID) and placing it into a variable, comparing it to our object in Session, and then taking action.  The pseudo code would look similar to:

If record in memory’s student Id == the row student Id selected, then remove the color from the row and set the record’s student id to nothing because we’re “deselecting” that student”.

If the record in memory’s student Id != the row student Id selected, then color it light green and set our record’s student Id to the selectedStudent variable (which happens to be the second cell’s text value).  We’re “selecting” this row.

So, now that we’ve updated the record in session to the “selected” student, we’re ready to close our popup.

Close Button

This code will vary for EVERYONE depending on what they’re using the popup for.  You could be populating a form on your parent web page, you could be modifying a database, you could be sending an online order to Pizza Hut for pizza (I’m hungry, send food, Pizzahut.com is blocked here. )

For me, I populate a placeholder back on the primary web form with a HyperLink control (that opens a popup that allows the user to view details about the student, but that’s beyond the scope of this).

protected void AddStudentsCloseButton_Click(object sender, EventArgs e)

{

Incident incident = (Incident)Session[“Incident”];

if (incident.StudentId != 0)

{

HyperLink hl;

hl = new HyperLink();

StudentRecord student =

Students.GetStudentRecordByStudentId(incident.StudentId, false);

hl.Text = student.FullName;

hl.NavigateUrl = “javascript:;”;

string popupWindowUrl =

String.Format(“window.open(‘ViewStudentInformation.aspx?

StudentId={0}’, null, ‘{1}’);”, studentId, popupWindowAttributes);

hl.Attributes.Add(“onclick”, popupWindowUrl);

placeholder.Controls.Add(hl);

placeholder.Controls.Add(UITools.InsertLineBreaks(1));

}

}

I could encorporate that into the RowCommand, but I didn’t want to constantly be updating the control incase the user got click happy and was selecting… unselecting… selecting.. unselecting.. etc.

Styles

A quick note is to the styles I used.  I like the alpha opacity blending to give that “dimmed” effect—looks very sweet and helps reiterate to users that they should pay attention to the bright window in front of them.  I also have the display: none commented out still.  See the post here for details.

.PopupPanel

{

width: 500px;

border: solid 2px #5D7B9D;

background-color: #F5F5DC;

padding: 10px 10px 10px 10px;

/* display: none; This won’t work due to a “bug” with the ModalPopup AJAX Control */

}

.ModalBackground

{

background-color: Gray;

filter: alpha(opacity=75);

}

  1. August 17, 2007 at 11:53 am

    After reading all of your AJAX-related posts you are inspiring me to step my ASP.NET AJAX game up. I’ve just liked the thrill of creating roll-your-own AJAX functionality for so long.

  2. August 17, 2007 at 12:08 pm

    True, and there are definately still occassions I push and pull my own information… but, the efficiency battle is a long and hard one–especially in my field, public education, where the “end product” has absolutely nothing to do with technology (our product is educating kids, the systems I create simply support that).

    If someone, even if I was using Google, Adobe, or another company’s AJAX framework, it’s still creating the building blocks and letting THEM worry about the details. My responsibility is understanding how it works and why… Thankfully, they’ve provided a lot of documentation and even, for like the AJAX Control Toolkit, the entire source code to peruse.

    It’s not “bad” to want to roll your own, but you gotta weigh efficiency vs. functionality.🙂 No new wheel creations here…🙂

  3. Antony
    September 14, 2007 at 11:10 am

    Hi there, you mention in your entry that “Paging is possible within the popup!”. I’ve tried for hours and I must be missing something.

    UpdatePanel is inside Popup Panel but I am using master pages and have an updatepanel across the content.

    Can you please post/email source so that I can check what I’m doing wrong.

    Thanks,
    Ants

  4. September 14, 2007 at 11:23 am

    Antony-

    How are you calling your PageIndexChanging on the gridview? From what I’ve seen, you have to anticipate that (since the UpdatePanel is “posting back” on Paging), you need to reload the data source.

    Here’s an example from the code above (I was using business objects in the post’s code):

    // Pull the data source from session (or wherever)
    GridView.DataSource = (DataTable) Session[“MyData”];

    // Set to the “new page”.
    GridView.PageIndex = e.NewPageIndex;

    // Rebind the data.
    GridView.DataBind();

    I’ll double check when I get back home tonight and post up if there’s any difference.

  5. Dinh Dinh
    October 10, 2007 at 6:48 pm

    After reading your post I would like to do the same but I could not get the StudentLookupSearchButton_Click to fire. The moment I click on Search the popup display with an empty grid. The post back did not occur to fill the grid with the search info. Am i missing somthing?

    Thanks for a great post.
    dinh

  6. October 11, 2007 at 4:42 am

    Do you have your grid inside an UpdatePanel? Post up your code (or email me at tiredstudent@gmail.com) and let’s take a look.🙂

  7. Dinh Dinh
    October 11, 2007 at 11:03 am

    Thank you for your reply. I found a way to make it work. I assigned mpe TargetControlID to a hidden button control. Therefore, when the user click the search button it will fired search_onclick event and fill in the grid.

    Without your sharing knowledge, I would never able to do this.

    Many many thanks,
    dinh.

  8. Joel WZ
    April 4, 2008 at 10:22 am

    I am looking at the code here and am having a little trouble piecing it all together. Do you have the code where you can up load it, so it will be a little more clear? I am specifically looking at the placement and contents of the various panels, update panels, etc.

    Thanks.

  9. April 7, 2008 at 10:30 am

    Joel-

    Sure, I’ll work up an example and post it up.

  10. April 7, 2008 at 1:06 pm

    Joel –

    Okay, here ya go. The same concepts apply and this code should stand on it’s own–it’s pretty heavily code commented. It uses the Northwind database to pull up a MPE, select a product, then pass that product via Session back down to the calling page.

    Download File here

    Hope this helps!

  11. Pranil
    April 16, 2008 at 10:34 am

    I have a masterpage and four content pages and in one of the content pages theres a gridview and a modalpopupextender. i need to popup an image on click of on of the columns in the grid. I am trying to do it, but when the popup shows up, the page behaves very weird.
    the page becomes like very large and we can keeep on scrolling!!!

    Could you let me know whether this works with master pages?

  12. Chau
    April 22, 2008 at 4:24 pm

    I was curious if you have the source code available anywhere?

  13. April 23, 2008 at 3:28 pm

    @Chau – Yeah, look a few comments up, I posted up a rendition of the source code back on 7 April 08.

  14. David
    April 25, 2008 at 1:42 pm

    David, thank you for sharing! Very nice code!

  15. Chau
    April 29, 2008 at 1:40 pm

    David, do you have your code sample in VS2005?

  16. April 30, 2008 at 5:38 am

    @Chau-

    No, unfortunately, I don’t. The project could easily be translated to VS2005 and .NET 2.0 by simply referencing the the v1.0 version of ASP.NET AJAX and replacing the LINQ I used for the data binding with simple DataTables/DataReaders.

    The overall functionality of the GridView, ModalPopupExtender, and such remains the same.

  17. August 30, 2008 at 7:12 am

    I couldn’t see images in your post.Links seems broken.

  18. August 30, 2008 at 8:55 am

    @Michael-

    Fixed. Heh, this post is old enough that it was pointing to the wrong library URL for the images. Thanks for pointing it out!

  19. Kelvin
    December 21, 2008 at 8:30 pm

    Any idea how to pass the selected row value to parent textbox?

    I tried this

    txt_CustomsStationCode.Text = row.Cells[1].Text.ToString();

    in RowCommand but it is not working.

  20. Francisco
    February 8, 2009 at 1:06 pm

    1) You are saving your collection using Session
    –> Session[“LookupStudentCollection”] = students; Students.GetStudentRecordByStudentId(incident.StudentId, false) <–

    You can just recover it from the Session
    Session(“LookupStudentCollection”)[StudentLookupGridView.SelectedIndex]

    (if you need multiselect, save RowIndex and not Student id)

    Regards!
    Francisco.

  21. Francisco
    February 8, 2009 at 1:10 pm

    sorry, last post has missing words.

    1) you are saving your collection using Session
    Session[“LookupStudentCollection”] = students
    Thats ok, you dont need to requery at paging.

    2) Finally you recover the selected student
    student=Students.GetStudentRecordByStudentId(incident.StudentId, false)

    Why do you requery if you have the entire collection in Session ?
    Session(”LookupStudentCollection”)[StudentLookupGridView.SelectedIndex]

    (if you need multiselect, save RowIndex and not Student id)

    Regards!
    Francisco.

  22. self-made
    June 9, 2009 at 3:00 pm

    Any chance you can post the code for the project above. I need exactly what you have, but I’m having trouble getting it to work correctly. I’m using a DataSet call for the data.

  1. August 14, 2007 at 3:15 pm
Comments are closed.
%d bloggers like this: