Multiple Modal Popups with the ASP.NET Ajax Toolkit

At the moment I’m building a CMS with ASP.NET, ASP.NET Ajax and the ASP.NET Ajax Toolkit. One of the great features that the AJAX Toolkit provides us is the possibility of adding modal popups.

I’m using them for gridviews that contains a lot of columns, and cannot be displayed in the page without the horizontal scroll. My solution for that is displaying the more important data, and then, when a row is selected, a detailform is displayed with all the data in a popup panel. My solution is based on Matt Berseth excellent post: Master-Detail with the GridView, DetailsView and ModalPopup Controls. This solves the problem of editing rows, but what happens when we want to add a new one?

The gridview control doesn’t have a built-in way of adding new items. One standard way of solving this is adding the add form in the footer of the gridview, but we don’t have the horizontal space needed for it if we have more data than the displayed on the gridview!

I planned to add a “Add element” link at my page, and adding a new popup for adding data. But it didn’t worked. My search of “multiple modal popups” didn’t give me any solutions. So I looked at what was happening there, and I created a simple test page like this:

    <asp:LinkButton ID="lnk" runat="server" Text="hi"></asp:LinkButton>
    <br />
    <asp:LinkButton ID="lnk2" runat="server" Text="hi2"></asp:LinkButton>
    <ajax:ModalPopupExtender ID="mpe" runat="server" TargetControlID="lnk" PopupControlID="pnl"
        CancelControlID="close" />
    <ajax:ModalPopupExtender ID="mpe2" runat="server" TargetControlID="lnk2" PopupControlID="pnl2"
        CancelControlID="close2" />
    <asp:Panel ID="pnl" runat="server" CssClass="popupPanel">
        <div>
            Hi!!!
        </div>
        <asp:Button ID="close" runat="server" Text="Close" />
    </asp:Panel>
    <asp:Panel ID="pnl2" runat="server" CssClass="popupPanel">
        <div>
            Hi2222!!!
        </div>
        <asp:Button ID="close2" runat="server" Text="Close" />
    </asp:Panel>

If I show the first panel, and hide it, the second panel is never shown.
The problem is that, in the generated HTML code, the second panel is a child of the first one, instead of being at the same level on the DOM tree.

IMHO this is an Ajax Control Toolkit bug, and I hope that I’ll find time, and I will take a look and send a patch. But for now, I used a workaround. I placed the modal popup panels inside of another one wrapping each one, and it did the trick.

Hope this helps somebody.

UPDATE 2008/03/03:
Merenzo has resolved the mistery. See the comments.

28 Responses

  1. This did the trick. I was having the exact same issue.

    Thanks!!

  2. Подскажите шооблончег под WordPress 2.6.2, чтобы был похож на ваш penyaskitodice.wordpress.com.

    Заранее благодарю)

  3. Hi Hauxula,

    This theme is Digg 3 Columns

    Hope this helps.

    PS: Please next time try to write in English, so I don’t have to bother my Russian friends (thanks Zitun)! 🙂

  4. Hello, I have the same problem. I followed your suggestion but i couldn’t get it to work. Could you post the working code?

    Jason

  5. Hi Jason,

    I sent it to you by mail. Hope it helps.

  6. +1 к предыдущему комменту 🙂

  7. Can you send me the code too?

  8. Hiya – I found this related post:

    http://forums.asp.net/p/1157697/2719378.aspx

    It claims that the problem is due to a missing semicolon in the AJAX script. Just wrapping the panel in another panel *usually* works, but doesn’t always (it didn’t in my case), as you can’t always guarantee that the offending line of script will be implicitly “ended” by whatever AJAX script is generated next.

    However – once you’ve added the wrapping panel (e.g. “AjaxBugWorkaroundPanel”), you can then explicitly “end” the offending script by outputting your own semicolon as follows:

    protected void AjaxBugWorkaroundPanel_PreRender(object sender, EventArgs e)
    {
    ScriptManager.RegisterStartupScript((Control)sender, sender.GetType(), Guid.NewGuid().ToString(), “;”, true);
    }

    All fixed! Who would’ve thought it. 🙂

    cheers
    merenzo.

  9. ps: Specifically, in my case, I added the wrapping around the offending control only.

    HTH!

    cheers
    merenzo.

  10. ps: Specifically, in my case, I added the wrapping asp:Panel around the offending ajax:ModalPopupExtender control only.

    HTH!

    cheers
    merenzo.

  11. Thanks Merenzo, I’ll update the post accordingly.

  12. Прикольная статья, по-моему что вам нужно в какие нибудь журналы специальные писать 🙂

  13. very useful info, thanks.

  14. Hi Christian, could I ask for code also? as i am unsure of wrapping Panel. Does solution also include Merenzo advice? Many thanks

  15. How come I still have problem?

  16. using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Data;
    using System.Data.SqlClient;
    using System.Text;

    namespace ModalPopupDemo
    {
    public partial class _Default : System.Web.UI.Page
    {
    protected void Page_Load(object sender, EventArgs e)
    {
    }

    private readonly string connectionString =
    “Data Source=ips-kraken;Initial Catalog=SPR;Integrated Security=True”;

    private void UpdateDB(string cmdString)
    {
    SqlConnection connection = new SqlConnection(connectionString);
    SqlCommand command = new SqlCommand(cmdString.ToString(), connection);
    try
    {
    connection.Open();
    command.ExecuteNonQuery();
    }
    catch (SqlException ex)
    {
    throw ex;
    }
    finally
    {
    if (connection.State != ConnectionState.Closed)
    connection.Close();
    }
    }

    private string GetUserID(string userName)
    {
    string userID = “”;

    StringBuilder selectCommand = new StringBuilder();
    selectCommand.Append(“SELECT UserID FROM [SPR].[dbo].[sprUsers] “);
    selectCommand.AppendFormat(“WHERE UserName=\'{0}\'”, userName);

    SqlConnection connection = new SqlConnection(connectionString);
    SqlCommand command = new SqlCommand(selectCommand.ToString(), connection);
    try
    {
    connection.Open();
    SqlDataReader dr = command.ExecuteReader();

    while (dr.Read())
    {
    userID = dr[“UserID”].ToString();
    }
    dr.Close();
    }
    catch (Exception ex)
    {
    throw ex;
    }
    finally
    {
    if (connection.State != ConnectionState.Closed)
    connection.Close();
    }

    return userID;
    }

    protected void btnEdit_Click(object sender, EventArgs e)
    {
    //mpeEditUser.Hide();
    try
    {
    StringBuilder updateCommand = new StringBuilder(“UPDATE [SPR].[dbo].[sprUsers] SET “);
    updateCommand.AppendFormat(“UserName='{0}’, “, txtUserName.Text);
    updateCommand.AppendFormat(“Extension='{0}’, “, txtExtension.Text);
    updateCommand.AppendFormat(“Email='{0}’ “, txtEmail.Text);

    updateCommand.AppendFormat(“WHERE UserID='{0}'”, GetUserID(txtUserName.Text));
    UpdateDB(updateCommand.ToString());
    }
    catch (Exception ex)
    {
    }
    }

    protected void lnkUserName_Click(object sender, System.EventArgs e)
    {
    LinkButton lbUserName = sender as LinkButton;
    GridViewRow gvr = (GridViewRow)lbUserName.NamingContainer;

    string username = lbUserName.Text;
    txtUserName.Text = username;
    txtExtension.Text = gvr.Cells[2].Text;
    txtEmail.Text = gvr.Cells[3].Text;

    mpeEditUser.Show();
    }

    protected void btnAdd_Click(object sender, EventArgs e)
    {
    //mpeAddUser.Hide();
    try
    {
    //check if the user already exists
    if (GetUserID(TextBox1.Text) != “”)
    {
    throw new Exception(“The user already exists!”);
    }

    //insert a new user
    StringBuilder insertCommand = new StringBuilder();
    insertCommand.Append(“INSERT INTO [SPR].[dbo].[sprUsers] “);
    insertCommand.Append(“([UserName], [Extension], [Email]) “);
    insertCommand.AppendFormat(“VALUES (‘{0}’, ‘{1}’, ‘{2}’)”, TextBox1.Text, TextBox2.Text, TextBox3.Text);
    UpdateDB(insertCommand.ToString());

    TextBox1.Text = “”;
    TextBox2.Text = “”;
    TextBox3.Text = “”;
    }
    catch (Exception ex)
    {
    }
    }

    protected void AjaxBugWorkaroundPanel_PreRender(object sender, EventArgs e)
    {
    ScriptManager.RegisterStartupScript((Control)sender, sender.GetType(), Guid.NewGuid().ToString(),”;”, true);

    //ScriptManager.RegisterStartupScript((Control)sender, sender.GetType(), Guid.NewGuid().ToString(), “\r\n;\r\n”, true);
    }
    }
    }

  17. I couldn’t post my aspx.

  18. can anyone send me the code example for wrapping panels in another, i m bit confused

  19. Highly recommended even for those who missed the two golden ages
    of the video arcade, Westfield Arcade should also appeal
    to anyone who has ever looked back on their younger days while at life’s crossroads. Or, if the player feels comfortable at the current difficulty, choosing “about right” will keep the difficulty relatively the same. Reflecting international influences that are ancient, modern or immediately contemporary, the album presents to its listener mesmerizing grandeur, solemn beauty, intricate craftsmanship and sonic depth The Painted Caravan is likely to appeal to fans of Richard and Linda Thompson, Arcade Fire, The Decemberists, Smoke Fairies, Faun Fables, Beirut, Luminescent Orchestrii, PJ Harvey’s quieter
    moments and, of course, Dead Can Dance.

  20. Неплохой топик

Leave a comment