WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

ModalPopup を別ページから非表示

by WebSurfer 2013年1月27日 16:52

Ajax Control Toolkit の ModalPopup 内の iframe に別ページを表示し、その別ページに配置されているボタンをクリックして ModalPopup を非表示にする方法の紹介です。

ModalPopup はクライアントスクリプトで非表示にできます。それには、Modalpopup をページに配置するとダウンロードされるクライアントスクリプトに定義されている hide メソッドを使います。

従って、iframe に表示するページの適当な DOM に click イベントのリスナーを仕掛けて、それで hide メソッドを起動すれば ModalPopup を非表示にできます。

ただし、iframe に表示するページは親ページと同じドメインのものでないと DOM が取得できないので注意してください(クロスサイトスクリプト対策だそうです)。

そのサンプルコードを以下に書いておきます。また、実際に動かして試すことができるよう 実験室 にアップしました。興味のある方は試してみてください。

親ページ

<%@ Page Language="C#" %>
<%@ Register Assembly="AjaxControlToolkit" 
    Namespace="AjaxControlToolkit" 
    TagPrefix="asp" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
 
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript">
    //<![CDATA[

        // iframe 内の document オブジェクトを取得。
        // contentWindow は IE 用。
        // contentDocument は Firefox 用。
        function iframeRef(frameRef) {
            return frameRef.contentWindow ?
                frameRef.contentWindow.document : 
                    frameRef.contentDocument;
        }

        function hideModalPopup() {
            var modalPopup = 
                $find('programmaticModalPopupBehavior');
            modalPopup.hide();
        }

        function showModalPopup() {
            var ifm = iframeRef($get('iframe1'));
            var btn = ifm.getElementById('hideButton');
            // hide するとリスナーも解除されてしまうので、
            // (btn.click が null になることで確認できる)
            // ModalPopup を表示するたびリスナーをアタッチ
            // する必要がある。
            if (btn.onclick == null) {
                if (window.addEventListener) {
                    btn.addEventListener('click',
                                         hideModalPopup, 
                                         false);
                } else if (window.attachEvent) {
                    btn.attachEvent('onclick', 
                                    hideModalPopup);
                }
            }

            var modalPopup = 
                $find('programmaticModalPopupBehavior');
            modalPopup.show();
        }
    //]]>
    </script>

    <style type="text/css">
        /*Modal Popup*/
        .modalBackground
        {
            background-color: Gray;
            filter: alpha(opacity=70);
            opacity: 0.7;
        }
        .popup
        {
            background-color: White;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ToolkitScriptManager 
        ID="ToolkitScriptManager1" 
        runat="server">
    </asp:ToolkitScriptManager>  

    <h1>ModalPopup Test</h1>

    <asp:Button ID="DummyButton" 
        runat="server"
        style="display: none;" />

    <input type="button" 
        value="Show ModalPopup" 
        onclick="showModalPopup();" />

    <asp:Panel 
        ID="Panel1" 
        runat="server" 
        CssClass="popup">
        <iframe 
            id="iframe1" 
            src="190-PageIniframe.aspx">
        </iframe>
    </asp:Panel>

    <asp:ModalPopupExtender 
        ID="ModalPopupExtender1" 
        runat="server"
        TargetControlID="DummyButton" 
        BehaviorID="programmaticModalPopupBehavior" 
        BackgroundCssClass="modalBackground" 
        PopupControlID="Panel1">
    </asp:ModalPopupExtender>
    </form>
</body>
</html>

iframe に表示するページ

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <h1>Page in iframe</h1>
        <input type="button" 
            id="hideButton" 
            value="Hide ModalPopup" />
    </div>
    </form>
</body>
</html>

Tags: ,

AJAX

ToolkitScriptManager と gzip 圧縮

by WebSurfer 2012年11月21日 21:37

Internet Explorer (IE) の「インターネットオプション」の「詳細設定」タブで、「HTTP 1.1 を使用する」のチェックを外すと、Ajax Control Toolkit が動かないという話の紹介です。(プロキシサーバー経由になる場合は「プロキシ接続で HTTP 1.1 を使用する」のチェックを外す)

「HTTP 1.1 を使用する」のチェックマークを外す

ググって見つけた CodePlex のページ ToolkitScriptManager ignores accept-encoding http header を読んで原因がわかりました。

簡単に言うと、原因は、ToolkitScriptManager が常に gzip で圧縮したスクリプトファイルを送信するのに、IE は「HTTP 1.1 を使用する」にチェックを入れないと解凍しないことです。

詳しく書くと、以下の通りです。

  1. ToolkitScriptManager は、Microsoft Ajax Library を外部スクリプトファイルとして HTTP ハンドラ経由でブラウザにダウンロードさせるため、script 要素の src 属性に ScriptResource.axd?d=...&t=... と設定した初期ページをブラウザに返します。

    クエリ文字列のパラメータ d には、HTTP ハンドラが取得すべきファイルの指定と、送信時に圧縮するか否かの指示が含まれています。(パラメータ d, t の詳細については MSDN マガジンの ASP.NET AJAX アプリケーションの国際化 を見てください)
  2. IE の設定で「HTTP 1.1 を使用する」にチェックが入っている場合、要求ヘッダには Accept-Encoding: gzip, deflate が含まれます。チェックを外すと Accept-Encoding は含まれなくなります。

    ASP.NET 標準の ScriptManager の場合は、Accept-Encoding の有無を見て、初期ページに指定される ScriptResource.axd?d=...&t=... のパラメータ d を変えてきます。(Accept-Encoding が無ければ非圧縮、Accept-Encoding: gzip, deflate が含まれれば gzip 圧縮がパラメータ d に指定される)
  3. ところが、Ajax Control Toolkit の ToolkitScriptManager の場合は、要求ヘッダに Accept-Encoding があってもなくても、初期ページに指定する ScriptResource.axd?d=...&t=... は同じです。パラメータ d は gzip 圧縮の指定となります。

    つまり、IE の設定で「HTTP 1.1 を使用する」のチェックを外しても/外さなくても、サーバーからHTTP ハンドラ経由で受け取るスクリプトファイルは gzip で圧縮されたものになります。
  4. 一方、IE の設定で「HTTP 1.1 を使用する」のチェックを外すということは、IE では圧縮ファイルは解凍されないということを意味します。(応答ヘッダに Content-Encoding: gzip が含まれていても無視されます)。
  5. 結果、IE は Microsoft Ajax Library のスクリプトを解析できず、Ajax Control Toolkit が動かないということになります。(「文字が正しくありません。」とか「'Sys' は宣言されていません。」などのエラーが出ます)

IE8, IE9 で検証してみましたが、同じ問題が出ます。

いまどき「HTTP 1.1 を使用する」のチェックを外すことはないでしょうから実際に問題が出ることはなさそうですが、こういう問題もあるということは ASP.NET Web アプリケーションの開発者なら知っておいたほうがよさそうだと思って書いてみました。

Tags: ,

AJAX

ASP.NET AJAX でページの静的メソッド呼び出し

by WebSurfer 2012年8月18日 16:32

ASP.NET の AJAX 機能を使って、ブラウザからクライアントスクリプトでサーバー側のメソッドを呼び出し、データを受け取って表示する方法を、先の記事 ASP.NET AJAX と Web サービス で紹介しました。

その例では、呼び出す相手は Web サービス (.asmx) のメソッドでしたが、それ以外に、自分のページ (.aspx) の静的メソッドを呼び出すことも可能です。

そのためのポイントは、簡単に書くと以下の 3 点です。

  1. ScriptManager で EnablePageMethods を true に設定。
  2. クライアントスクリプトから呼び出すサーバー側のメソッドは public static にして WebMethodAttribute 属性を付与。
  3. クライアントスクリプトからは、プロキシクラス PageMethods を通じて呼び出し。プロキシクラス PageMethods のコードはサーバーで自動生成され、html ソースにインラインで含まれてブラウザに送信されます。(呼び出し先が Web サービスの場合は WebService.asmx/js というような外部ファイルになります)

詳しくは、MSDN ライブラリの クライアント スクリプトへの Web サービスの公開 の「ASP.NET Web ページ内の静的メソッドの呼び出し」というセクションを参照してください。

サンプルコードは上に紹介した MSDN ライブラリのページにもありますが、先の記事 ASP.NET AJAX と Web サービス で書いた Web サービスの例を、Page の静的メソッドを使う方法に置き換えたサンプルコードを以下に書いておきます。

(1) Web ページ (173-ASPNETAjaxAndStaticMethod.aspx)

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.Linq" %>
<%@ Import Namespace="System.Web.Services" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

    public class Car
    {
        public string Make;
        public string Model;
        public int Year;
        public int Doors;
        public string Colour;
        public float Price;
    }

    static protected List<Car> Cars = new List<Car>{
        new Car{Make="Audi",Model="A4",Year=1995,
            Doors=5,Colour="Red",Price=2995f},
        new Car{Make="Ford",Model="Focus",Year=2002,
            Doors=5,Colour="Black",Price=3250f},
        new Car{Make="BMW",Model="5 Series",Year=2006,
            Doors=4,Colour="Grey",Price=24950f},
        new Car{Make="Renault",Model="Laguna",Year=2000,
            Doors=5,Colour="Red",Price=3995f},
        new Car{Make="Toyota",Model="Previa",Year=1998,
            Doors=5,Colour="Green",Price=2695f},
        new Car{Make="Mini",Model="Cooper",Year=2005,
            Doors=2,Colour="Grey",Price=9850f},
        new Car{Make="Mazda",Model="MX 5",Year=2003,
            Doors=2,Colour="Silver",Price=6995f},
        new Car{Make="Ford",Model="Fiesta",Year=2004,
            Doors=3,Colour="Red",Price=3759f},
        new Car{Make="Honda",Model="Accord",Year=1997,
            Doors=4,Colour="Silver",Price=1995f}
    };

    [WebMethod]
    public static List<Car> GetCarsByDoors(int doors)
    {
        var query = from c in Cars
                    where c.Doors == doors
                    select c;

        return query.ToList();
    }    
    
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>ASP.NET AJAX to call static method</title>
  <script src="Scripts/jquery-1.4.1.js" type="text/javascript">
  </script>
</head>
<body>
  <form id="form1" runat="server">
    <asp:ScriptManager ID="ScriptManager1" 
      runat="server" 
      EnablePageMethods="True">
      <Scripts>
        <asp:ScriptReference 
          Path="~/173-ASPNETAjaxAndStaticMethod.js" />
      </Scripts>
    </asp:ScriptManager>
    <div>
      Number of doors: 
      <asp:DropDownList ID="ddlDoors" runat="server">
        <asp:ListItem>2</asp:ListItem> 
        <asp:ListItem>3</asp:ListItem>
        <asp:ListItem>4</asp:ListItem>
        <asp:ListItem>5</asp:ListItem>
      </asp:DropDownList>   
    </div>
    <input 
      type="button" 
      id="Button1" 
      value="Get Cars" 
      onclick="getCars($('#<%=ddlDoors.ClientID%>').val());" /> 
    <div id="output"></div>
  </form>
</body>
</html>

(2) JavaScript (173-ASPNETAjaxAndStaticMethod.js)

var serviceProxy;

// プロキシの初期化
function pageLoad() {
    serviceProxy = new PageMethods();
}

// ボタンクリックで呼び出されるメソッド  
function getCars(doors) {
    serviceProxy.GetCarsByDoors(doors, Succeeded, Failed);
}

// AJAX 通信が成功したときに呼び出され、戻ってきたデータ
// を処置するコールバック関数。
// 引数 cars は JSON 文字列ではなく、パース済みのオブジェ
// クト。.NET 3.5 で追加された d パラメータはプロキシで
// 適切に処置されるらしい。
function Succeeded(cars) {
    $('#output').empty();
    $.each(cars, function (index, car) {
        $('#output').append(
            '<p><strong>' + car.Make + ' ' +
            car.Model + '</strong><br /> Year: ' +
            car.Year + '<br />Doors: ' +
            car.Doors + '<br />Colour: ' +
            car.Colour + '<br />Price: £' +
            car.Price + '</p>');
    });
}

// 通信に失敗したとき呼び出されるコールバック関数。 
function Failed(error, userContext, methodName) {
    if (error !== null) {
        var msg = "An error occurred: " +
            error.get_message();
        $('#output').text(msg);
    }
}

if (typeof (Sys) !== "undefined") {
    Sys.Application.notifyScriptLoaded();
}

なお、上記 Web ページの静的メソッド GetCarsByDoors は jQuery.ajax からも呼び出せます。先の記事 jQuery AJAX と Web サービス で紹介したコードで、呼び出し先 (url) を変更するだけです。呼び出し先の Web ページの URL が上の例のように 173-ASPNETAjaxAndStaticMethod.aspx とすると、以下のような感じです。

// 前略 
function getCars() {
  $.ajax({
    type: "POST",
    url: "173-ASPNETAjaxAndStaticMethod.aspx/GetCarsByDoors",
    data: "{doors: " + $('#ddlDoors').val() + "}",
// 後略

その場合、上で述べた ScriptManager は不要ですし、プロキシにアクセスするスクリプト(上の例で言うと 173-ASPNETAjaxAndStaticMethod.js ファイル)も不要です。それゆえ、呼び出し元は .aspx ページである必要はなく、静的な .html ページとしても OK です。

Tags:

AJAX

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年5月  >>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar