Как стать автором
Обновить

Всплывающие модальные окна на jQuery в ASP.NET

Время на прочтение 6 мин
Количество просмотров 13K
В данной статье я расскажу о своём опыте реализации всплывающего модального окна с некой формой и submit-кнопкой на ASP.NET + jQuery и с теми ошибками, с которыми я столкнулся.



На работе перед началом создания нового проекта (веб сайт) я решил попробовать перейти с клиентской части библиотеки Microsoft AJAX на jQuery. Оснований для этого было несколько, но не об этом сейчас речь.

Дошло дело до всплывающих модальных окон и надо было найти соответствующий плагин. Сначала я попробовал jqModal, но наткнулся на баг в IE7 (мой bug report). После чего я решил использовать jQuery UI dialog, т.к. мне понравилась сама библиотека jQuery UI. Забегая вперёд отмечу, что ThickBox имеет аналогичную проблему той, которую я сейчас опишу.

На тестовом сайте я решил реализовать всплывающее модальное окно для входа пользователя на сайт. Т.е. при клике на линк «Вход» должно показаться всплывающее окошко (модальное) с двумя текстовыми полями (email (как login)/пароль) и двумя кнопками (ок/отмена).

Собственно, создал контрол, который должен был обеспечивать появление этой формы при клике на любые ссылки с классом «lbPopupLink»:

<%@ Control Language=«C#» AutoEventWireup=«true» Inherits=«Website.Controls.LoginBox» CodeBehind=«LoginBox.ascx.cs» %>
<asp:Panel runat=«server» ID=«panelMain» ToolTip=«Введите ваш email и пароль для входа на сайт»>
   <asp:Label runat=«server» ID=«Label1» AssociatedControlID=«txtEmail» CssClass=«req» Text=«Ваш email»></asp:Label>:
   <br />
   <asp:TextBox runat=«server» ID=«txtEmail» AutoCompleteType=«Email» MaxLength=«255»></asp:TextBox>
   <asp:RequiredFieldValidator runat=«server» ID=«RequiredFieldValidator1» ControlToValidate=«txtEmail» Display=«Dynamic» ErrorMessage=«Необходимо ввести email.»></asp:RequiredFieldValidator>
   <br />
   <br />
   <asp:Label runat=«server» ID=«Label2» AssociatedControlID=«txtPassword» CssClass=«req» Text=«Пароль»></asp:Label>:
   <br />
   <asp:TextBox runat=«server» ID=«txtPassword» TextMode=«Password» MaxLength=«255»></asp:TextBox>
   <asp:RequiredFieldValidator runat=«server» ID=«RequiredFieldValidator2» ControlToValidate=«txtPassword» Display=«Dynamic» ErrorMessage=«Необходимо ввести пароль.»></asp:RequiredFieldValidator>
   <br />
   <br />
   <asp:CheckBox ID=«chkRememberMe» runat=«server» Text=«запомнить меня.» />
   <br />
   <br />
   <asp:Literal ID=«strError» runat=«server» EnableViewState=«False»></asp:Literal>
   <br />
   <asp:Button ID=«butOk» runat=«server» Text=«Войти» OnClick=«butOk_Click» />
   <asp:Button ID=«butCancel» runat=«server» Text=«Отмена» CausesValidation=«false» />
</asp:Panel>
<script type=«text/javascript»>
   $(document).ready(function()
   {
      $("#<%= this.panelMain.ClientID %>").css(«display», «block»);
      $("#<%= this.panelMain.ClientID %>").dialog
      ({
         autoOpen: false,
         modal: true,
         width: 400,
         height: 300,
         dialogClass: «popupDialog»,
         resizable: false,
         overlay: { opacity: 0.5, background: «black» }
      });

      $(".lbPopupLink").click(function()
      {
         $("#<%= this.panelMain.ClientID %>").dialog(«open»);
         $("#<%= this.txtEmail.ClientID %>").focus();
         return false;
      });

      $("#<%= this.butCancel.ClientID %>").click(function()
      {
         $("#<%= this.panelMain.ClientID %>").dialog(«close»);
         return false;
      });
   });
</script>
* This source code was highlighted with Source Code Highlighter.


(не забывайте, что тут я javascript код прописываю прямо на странице, что, в принципе, не есть хорошо, т.к. если я контрол поставлю на странице дважды, то получиться дублирующий javascript код — в этом случае лучше использовать ClientScriptManager.RegisterClientScriptBlock; но т.к. данный контрол я точно собирался использовать только один раз на страницу и в целях упрощения статьи я оставлю всё как есть)

Всё заработало, но не до конца: при клике на ссылку с классом «lbPopupLink» действительно появлялось окошко, но при клике на кнопку «Ok» ничего не происходило. Разбираясь и переписываясь с разработчиками jQuery UI я понял в чём дело: чтобы побороть глюки с z-index-ом и stacking-ом в IE при отображении диалога jQuery UI dialog при показе окошка перемещает его внутри DOM-а в самый конец страницы, располагая его прямо в конце <body>. Обычно на других платформах этого не замечали, т.к. просто для каждой такой «всплывающей» формы делали обрамляющий <form> с нужным action и всё работало. Но в идеалогии ASP.NET <form> элемент должен быть только один. Получалось, что наша форма с <input type=«submit» value=«Ок»… /> переносилась за пределы одной единственной формы и потому клик на кнопку «Ок» ничего не делал. Об этом можно почитать в моей переписке с разработчиками. В этой переписке они (разработчики) сами предложили несколько временных решений и я реализовал одно из них: при нажатии на «Ок» диалог перед уничтожением клонируется и вставляется обратно в форму ASP.NET (id=«aspnetForm»). Ради чего была написана маленькая функция. Там ещё был один «прикол» с IE: оказалось, что в IE при использовании jQuery.clone не копируются значения <input type=«password»… /> полей, потому пришлось их «ручками» перегонять. Собственно, сама функция вот (не пинайте — на jQuery работаю отсилы неделю):

// Global variables
var __passwordCloneValues;

//
// Function that will close jQuery UI dialog, clone it back to aspnet form and perform submit.
// Should be applied to the dialog.
//
// Arguments:
//      butOkId — id of the submit button
//
$.fn.extend({
   dialogCloseAndSubmit: function(butOkId)
   {
      if (!Page_IsValid)
         return false;

      __passwordCloneValues = new Array();
      $(":password", $(this)).each(function()
      {
         __passwordCloneValues.push($(this).val());
      });
      __passwordCloneValues = __passwordCloneValues.reverse();

      var dlg = $(this).clone();
      $(this).dialog(«destroy»).remove();

      dlg.css(«display», «none»);
      $(«form:first»).append(dlg);
      $(":password", dlg).each(function()
      {
         $(this).val(__passwordCloneValues.pop());
      });
      $("#" + butOkId, dlg).click();

      return true;
   }
});
* This source code was highlighted with Source Code Highlighter.


И вот чем нужно дополнить наш javascript блок из начала статьи, чтобы использовать эту функцию:
$("#<%= this.butOk.ClientID %>").click(function()
{
   return $("#<%= this.panelMain.ClientID %>").dialogCloseAndSubmit($(this).attr(«id»));
});
* This source code was highlighted with Source Code Highlighter.


Вот, что получилось:


Исходный код всего тестового проекта.

PS: блин, для первого топика на хабре хотел покороче :|

Теги:
Хабы:
+20
Комментарии 17
Комментарии Комментарии 17

Публикации

Истории

Работа

.NET разработчик
66 вакансий

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн