アーカイブ

Archive for the ‘Javascript’ Category

Visual Studio(Web Essentials)でCSSスプライトを作成する。

あんまり触っていなかったんですが、Web Essentialsってすごいですね。Webページのパフォーマンス改善をやっていたのですが、Web Essentialsのお陰でかなり作業がはかどりました。

Web Essentialsの概要については井上さんのブログがとても参考になります。

    CSSスプライトってなに?

    CSSスプライトは複数の画像ファイルを一つのファイルにまとめることで、ダウンロード回数を減らし、ページ全体の表示を高速にする手法です。

詳しいことは、Googleさんに聞いてください。

で、前からCSSスプライト処理には興味はあったんですが、一部の画像だけ変更されたり、画像が追加されたりした場合に、画像の再結合作業がめんどくさかったり、CSSを調整するのが面倒だったりしてよほど読み込み頻度が多いような画像以外は対応していなかったんですよね。

Visual Studio(Web Essentials)を使ったCSSスプライト

Web Essentialsを使うと、このCSSスプライト処理を簡単に行えるというわけです。しかも画像が変更された場合は自動的に再作成してくれるし、画像が追加された場合も簡単な作業でCSSスプライトを更新できます。

Web Essentialsがインストールされていない場合は、Visual Studioの拡張機能と更新からWeb Essentialsを選択してインストールしてください。Visual Studioギャラリーからダウンロードしてインストールすることもできます。

image

画像の結合と関連ファイルの作成

チェックボックスをイメージしたこんな2つの画像があるとします。

image

ソリューションエクスプローラーで結合したいファイルを選択後、コンテキストメニューから Web Essentials → Create image sprite… を順にクリックします。適当に名前をつけてSpriteファイルを保存します。

image image

spriteファイルの他に、png,css,less,map,scssと言ったファイルがソリューションに取り込まれます。

image

エクスプローラーでImagesフォルダーを見てみると、こんな感じにファイルたちが作成されています。lessやscssはcssファイルはcssを簡易に記述するためのCSS拡張メタ言語用のファイルです。mapファイルにはscssやless,cssを出力するための定義がJSON形式で記述されています。

image

画像を表示する

先ほど作成された、cssファイルを確認してみます。もちろんlessやscssからcssを生成したい場合はそちらを参照しても良いです。取り込んだ画像ファイルは、[フォルダー名_画像ファイル名(拡張子なし)]で表示用のクラスが定義されていることを確認できます。ちゃんとbackgroundにオフセットが指定されていますね。

/*
This is an example of how to use the image sprite in your own CSS files
*/
.Images-checkbox_off {
/* You may have to set 'display: block' */
    width: 16px;
    height: 16px;
    background: url('CheckboxSprite.png') 0 0;
}
.Images-checkbox_on {
/* You may have to set 'display: block' */
    width: 16px;
    height: 16px;
    background: url('CheckboxSprite.png') 0 -16px;
}

こんなHTMLを作成すれば画像を表示できます。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
    <link href="Images/CheckboxSprite.png.css" rel="stylesheet" />
</head>
    <body>
        <div class="Images-checkbox_on"></div>
        <div class="Images-checkbox_off"></div>
    </body>
</html>

表示できましたね。

image

画像の差し替え

画像を差し替えたい場合は、ファイルを差し替えるだけです。先ほどとは色合いが違う画像を同じ名前でVisual Studioに取り込んであげます。

image

いっぺんにファイルをソリューションフォルダーにドロップすると、アクセス拒否されるので、一つ一つドロップしてあげてください。取り込み後のImageフォルダーを見ると、結合画像も同時に更新されていることが確認できます。

image

画像の追加

Spriteに画像を追加する場合はSpriteを作り直しても良いですが、Spriteファイルに定義を追加してあげればSpriteファイルを保存したタイミングで再生成してくれます。filses要素に<file>/Images/ping.png</file>を追加しました。

<?xml version="1.0" encoding="utf-8"?>
<sprite xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://vswebessentials.com/schemas/v1/sprite.xsd">
  <settings>
    <!--Determines if the sprite image should be automatically optimized after creation/update.-->
    <optimize>true</optimize>
    <!--Determines the orientation of images to form this sprite. The value must be vertical or horizontal.-->
    <orientation>vertical</orientation>
    <!--File extension of sprite image.-->
    <outputType>png</outputType>
    <!--Determin whether to generate/re-generate this sprite on building the solution.-->
    <runOnBuild>false</runOnBuild>
    <!--Use full path to generate unique class or mixin name in CSS, LESS and SASS files. Consider disabling this if you want class names to be filename only.-->
    <fullPathForIdentifierName>true</fullPathForIdentifierName>
    <!--Use absolute path in the generated CSS-like files. By default, the URLs are relative to sprite image file (and the location of CSS, LESS and SCSS).-->
    <useAbsoluteUrl>false</useAbsoluteUrl>
    <!--Specifies a custom subfolder to save CSS files to. By default, compiled output will be placed in the same folder and nested under the original file.-->
    <outputDirectoryForCss />
    <!--Specifies a custom subfolder to save LESS files to. By default, compiled output will be placed in the same folder and nested under the original file.-->
    <outputDirectoryForLess />
    <!--Specifies a custom subfolder to save SCSS files to. By default, compiled output will be placed in the same folder and nested under the original file.-->
    <outputDirectoryForScss />
  </settings>
  <!--The order of the <file> elements determines the order of the images in the sprite.-->
  <files>
    <file>/Images/checkbox_off.png</file>
    <file>/Images/checkbox_on.png</file>
    <file>/Images/pin.png</file>
  </files>
</sprite>

追加されていますね。

image

画像やCSSの再生成なんかを後ろで勝手にやってくれるのは楽ですね。いや、ホント楽ですね。

カテゴリー:ASP.NET, Javascript タグ: , ,

ASP.NET Web APIのサービスをJSONPで呼び出す。

2014年7月9日 3件のコメント

MSDNフォーラムをのぞいたら、こんなスレッドがあったのでWeb APIの入門を兼ねていじってみます。

クロスドメインリクエストへの対応については松崎さんのブログで詳しくまとまっています。

JSONP などクロス ドメイン (Cross-Domain) 問題の回避と諸注意

Web Apiの追加

まずは何も考えずに、WebApiを一つ追加しましょう。

image image

名前はとりあえずUserControllerとかにしておきます。

image 

とりあえずそのまま動作を確認してみる

この状態で http://host/api/user/http://host/api/user/1 といったURLをリクエストすれば、[ “value1”, “value2" ] や “value” といったJSON文字列が取得できるはずです。

FiddlerやChromeのAdvanced Rest Clientなんかから確認してみましょう。

一応それっぽい文字列が帰ってきていますね。

image

jQueryから呼び出してみる。

jQueryのajax関数から呼び出すとするとこんなかんじですね。

$("#getUser").on("click", function () {
    var userId = $("#userId").val();
    $.ajax({
        url: "http://localhost:45924/api/user/" + userId,
        type: 'GET',
        dataType: 'json'
    }).success(function (data) {
        alert(data);
    }).error(function(data) {
        alert(data);
    });
});

ちゃんと返ってきました。

image

Web ApiをJSONPに対応させる。

Web ApiでJSONP形式で値を返したい場合は、NugetパッケージのWebApiContrib.Formatting.Jsonpを使うと簡単に実現できます。前述のパッケージを導入後、Global.asaxやWebApiConfigなどのクラスでコールバック付き(?callback=関数名)のリクエストを受け付けた場合にJSONP形式に整形するFormatterを登録します。

Public Module WebApiConfig
    Public Sub Register(ByVal config As HttpConfiguration)
        ' Web API の設定およびサービス

        ' Web API ルート
        config.MapHttpAttributeRoutes()

        config.Routes.MapHttpRoute(
            name:="DefaultApi",
            routeTemplate:="api/{controller}/{id}",
            defaults:=New With {.id = RouteParameter.Optional}
        )

        config.AddJsonpFormatter()
    End Sub
End Module

ちょっと見えづらいですが、Responseタブの中身を見ると、JSONP形式(a([“value1”, “value2”]))で結果が帰ってきたのを確認できます。

image

jQueryから呼び出す。

jQueryを使っている場合は、ajax関数のdataTypeパラメーターに”jsonp”を指定するだけですね。

$(function() {
    $("#getUser").on("click", function () {
        var userId = $("#userId").val();

        $.ajax({
            url: "http://localhost:45924/api/user/" + userId,
            type: 'GET',
            dataType: 'jsonp'
        }).success(function (data) {
            alert(data);
        }).error(function(data) {
            alert(data);
        });
    });
});
カテゴリー:ASP.NET, Javascript, Visual Basic

ASP.NET WebFormsとknockoutで自動的にテーブルを再表示する

久々にMSDNフォーラムを覗いたら、UpdatePanel + Timerでメモリーリークがどうのという話を見かけた。

Knockout + WCFでできるよと回答したものの、それだけだとちょっとあれなので、やり方を書いてみる。

プロジェクトはココからダウンロード出来ます。

プロジェクトにknockoutを組み込む

プロジェクトにknockout.jsが組み込まれていない場合は、パッケージマネージャーコンソールを開き、knockout.jsをインストールします。もしjQueryを使っていない場合は、ついでに組み込みます。

PM> Install-Package knockoutjs
PM> Install-Package jQuery

上記のコマンドを実行すると、プロジェクトにknockout-2.2.1.debug.jsとknockout-2.2.1.jsが追加されます。

image

Knockoutを参照する

マスターページなどに、先ほどインストールしたknockoutを参照します。(Site.Master)

<%@ Master Language="VB" AutoEventWireup="false" CodeBehind="Site.master.vb" Inherits="knockoutReload.Site" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/jquery-2.0.2.js")%>'></script>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/knockout-2.2.1.js") %>'></script>
    <asp:ContentPlaceHolder ID="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
        
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>

 

まずは静的にテーブルを表示する

WCFでデータを取得する前に、静的なページで表示できることを確認しておきましょう

今回は、knockoutのドキュメントページにあるサンプルをちょこっと変えて利用します。(WebForm1.aspx)

<%@ Page Title="" Language="vb" AutoEventWireup="false" MasterPageFile="~/Site.Master" CodeBehind="WebForm1.aspx.vb" Inherits="knockoutReload.WebForm1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<script type="text/javascript">
    $(function () {
        function AppViewModel() {
            var self = this;
            self.people = ko.observableArray([]);

            self.reflesh = function () {
                self.people.push({ firstName: 'Bert', lastName: 'Bertington' });
                self.people.push({ firstName: 'Charles', lastName: 'Charlesforth' });
                self.people.push({ firstName: 'Denise', lastName: 'Dentiste' });
            };
        }

        var viewModel = new AppViewModel();
        ko.applyBindings(viewModel);
        viewModel.reflesh();
    });    
</script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<div>
<table>
    <thead>
        <tr><th>First name</th><th>Last name</th></tr>
    </thead>
    <tbody data-bind="foreach: people">
        <tr>
            <td data-bind="text: firstName"></td>
            <td data-bind="text: lastName"></td>
        </tr>
    </tbody>
</table>
</div>
</asp:Content>

とりあえず実行するとこうなります。

image

サーバー側のサービスを作る

次に、knockoutから呼び出されるサービスを作成します。別途WCFサービスを作成しても良いのですが、ページメソッドでも対応できるので、今回はこちらを利用します。

まずは、クライアントにデータを返却するためのエンティティークラスを定義します。(People.vb)

<Serializable()>
Public Class People
    Public Property firstName As String
    Public Property lastName As String
End Class

続いて、ページ内にWebMethodでマークした静的メソッドを追加します。(WebForm1.aspx.vb)

Imports System.Web.Services

Public Class WebForm1
    Inherits System.Web.UI.Page

    <WebMethod()>
    Public Shared Function ReleshTable() As List(Of People)
        Return New List(Of People) From {
            New People With {.firstName = "Bert", .lastName = "Bertington"},
            New People With {.firstName = "Charles", .lastName = "Charlesforth"},
            New People With {.firstName = "Denise", .lastName = "Dentiste"}
        }
    End Function
End Class

クライアントからサービスを呼び出す

ページ初期化時にサーバー側に定義したサービスを呼び出して、クライアントのテーブルにバインドするように変更します。ViewModelに定義したrefleshメソッドを次のように変更します。定期的に呼び出したいので最後にsetTimeoutの記述を追加指定ます。

self.reflesh = function () {
    $.ajax({
        type: "POST",
        dataType: "json",
        contentType: "application/json; charset=utf-8",
        url: "WebForm1.aspx/ReleshTable",
        success: function (data) {
            self.people(data.d);
            setTimeout(self.reflesh, 5 * 1000);
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            alert(textStatus);
        }
    });
};

実行すると、先ほどと見た目は同じ結果が表示されますが、F12ツールで確認すると5秒毎に読み込んでいるのがわかります。

image

カテゴリー:ASP.NET, Javascript タグ:

Knockoutで取得したデータをjQueryMobileに反映する。

WebFormでJavascript主体なスマートフォン向けサイトを作ろう その5 #タイトルの付け方を変えました。

前回までで、サーバー側のWebServiceをJavascriptから呼び出し、結果を取得するところまで作成しました。

次に結果を画面に反映する部分を作成しましょう。

ViewModelの変更

前回取得したWebサービスの値をKnockout経由でView側に通知させます。

JQuery Mobileを直に利用している場合、DOMを変更したら各要素をrefleshしてあげないとスタイルが反映されないんだけれど、knockoutを利用した場合は特に何もせずに反映されるんですよね。ただ、サンプルなんかを見るとrefleshを発行しているものもあり。必要かどうかよくわかりません(汗。見た目問題なく動いているんですけれどね。

var viewModel = new (function () {
var local = this;
var service = new customerService();

this.keyword = ko.observable("");
this.検索結果 = ko.observableArray([]);
this.件数 = ko.computed(function () {
return local.検索結果().length;
});

this.find = function () {
local.検索結果.removeAll();
service.Find($, this.keyword(),
function (result) {
var data = result.d;
ko.utils.arrayPushAll(local.検索結果, data);
// $("#リストのID").listview('reflesh');
});
};
})();

配列と計算用のプロパティー

一覧表示用のデータ等は、通知に対応した配列(ko.observableArray)をプロパティーとして用意します。

件数などで、特定のプロパティーの値をそのまま利用できるようなプロパティーは、計算に対応したプロパティー(ko.computed)として定義してあげるとプロパティーの更新漏れなんかがなくて良いです。今回は検索結果を格納した配列の要素数がそのまま検索結果件数なので、検索結果().lengthを返却しています。

検索結果の追加

検索した結果は、ko.observableArrayなプロパティーに1件づつpushしていっても良いのですが、ko.utilsに配列をまるごとpushするユーティリティー(arrayPushAll)が用意されているので、こいつを利用しましょう。

observableArrayに追加する要素は、本来observableなプロパティーを持つクラスを指定できますが、今回はリストに表示するだけで、かつ各要素に対する変更も受け取る必要が無いので、WCFから受け取ったデータ(result.d)をそのまま配列に追加しています。

Viewの変更

以前作ったViewに結果リストを表示するためのリストと、結果件数を表示するためのラベルを追加します。

<%@ Page Title="" MasterPageFile="~/Site.Master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<div data-role="page" id="FindCustomerView">
<header data-role="header" data-position="fixed">
<h1>顧客検索</h1>
</header>
<div data-role="content">
<input type="text" data-bind="value: keyword"/>
<input type="button" value="検索" data-bind="click: find" />
<p>検索結果件数:<span data-bind="text: 件数"></span></p>
<ul data-role="listview" data-bind="foreach: 検索結果">
<li><a data-bind="attr: { href: 'Detail.aspx?jyu=' + ユーザーId }">
<h4><span data-bind="text: ユーザー名"></span></h4>
<p>(<span data-bind="text: ユーザーId"></span>)</p>
</a></li>
</ul>
</div>
</div>
</asp:Content>
listviewと配列のバインド
jQuery Mobileでリストを表示したい場合は、data-role属性でlistviewを指定します。
また、data-bind属性で、foreach: observableArrayなプロパティーを指定すると、配列をリストにバインドできます。
配列バインドのテンプレート
knockoutでは、foreachでバインディングした要素の配下を配列要素数分繰り返します。
検索結果という配列に3個の要素があったなら、この部分が3回繰り返されることになります。
<li><a data-bind="attr: { href: 'Detail.aspx?jyu=' + ユーザーId }">
<h4><span data-bind="text: ユーザー名"></span></h4>
<p>(<span data-bind="text: ユーザーId"></span>)</p>
</a></li>
この部分に関してはそれほど特筆する点はありませんね。実行してみると、liの部分がテンプレートで記述した要素通りに、3つ追加されているのを確認できます。
image
 
実行するとこんなかんじに表示されます。さて、一応表示までできましたね。

この画面から遷移する予定のDetail.aspx側(更新)も気が向いたら書きます。

image
 

過去へのリンクはこちらから

  • その1 はじめに
  • その2 ソリューション作成とライブラリの追加(knockout,jQuery,jQueryMobile)
  • その3 Knockoutを利用したViewModelの追加
  • その4 jQueryからASP.NETのWCF Serviceの呼び出し

jQueryからASP.NETのWCF Serviceの呼び出し

2012年6月19日 1件のコメント

WebFormでJavascript主体なスマートフォン向けサイトを作ろう その4

前回まででクライアント側のView-ViewModelの部分を作成したので、今回はクライアントのModelとそのModelが呼び出すサーバー側のサービスを作成していきます。今回は、knockout出てこないですね。WCFとJavascriptのお話です。

Webサービスの仕様

今回作成するサービスは、クライアントから渡されたキーワードをもとに検索を行い、検索にヒットしたデータの一覧を返すこととします。

WCFサービスとして作成するので、まずはデータコントラクトを作成します。今回はユーザーIdとユーザー名の2つを持つ簡単なエンティティークラスのリストを返却することします。データコントラクトはこんな感じになります。

Imports System.Runtime.Serialization

Namespace Entity
    <DataContract()>
    Public Class Customer
        <DataMember()>Property ユーザーId As String
        <DataMember()>Property ユーザー名 As String
    End Class
End Namespace

Webサービスの作成

次にWebサービスを本体を作成します。Visual Studioの新しい項目の追加から、「AJAX 対応 WCFサービス」を作成します。名前は、「FindService.svc」としておきます。

image

ここでは、ダミーの検索結果を返すメソッドFindを定義します。今回は、JavascriptとJSON形式のメッセージでやり取りしたいので、OperationContractにWebInvoke属性を追加して、Request、ResponseともにJSONでデータ交換を行うように宣言します。

<OperationContract()>
<WebInvoke(BodyStyle:=WebMessageBodyStyle.WrappedRequest, RequestFormat:=WebMessageFormat.Json, ResponseFormat:=WebMessageFormat.Json)>
Public Function Find(keyword As String) As List(Of Customer)
    Return New List(Of Customer) From {
            New Customer With {.ユーザーId = "karuakun", .ユーザー名 = "かるあくん"},
            New Customer With {.ユーザーId = "karua", .ユーザー名 = "かるあ"},
            New Customer With {.ユーザーId = "karukan", .ユーザー名 = "偽物"}
        }
End Function

クライアント側モデルクラスの作成(Webサービスの呼び出し)

実際にモデルクラスを作る前に、サーバーとはJSON形式でデータをやりとりするので、Javascriptオブジェクトをシリアライズ・デシリアライズするユーティリティークラスをひとつ導入しておきましょう。Nuget Package Consoleで、JSON2.jsをプロジェクトにインストールします。

PM> Install-Package json2
Successfully installed 'json2 1.0.2'.
Successfully added 'json2 1.0.2' to MobileTest.

クライアント側のモデルクラスを~/Script/Service以下に作成します。スクリプトの名前は、「CustomerService.js」としておきましょう。ちなみに、ソリューションはこんな感じで構成されています。

image

WebInvoke属性でマークしたWCFサービスのメソッドをjavascriptから呼び出す場合は、「WCFサービスのパス/メソッド名」で呼び出せます。WCFのパラメーター(data)はWCFのインターフェイスにあわせてJSON.stringifyメソッドでJSON文字列に変換します。

var customerService = (function () {
    var self = this;
    this.Find = function ($, keyword, successAction) {
        var data = JSON.stringify({keyword: keyword});
        $.ajax({
            type: "POST",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            url: "Service/CustomerService.svc/Find",
            data: data,
            success: successAction(response)
        });
    };
});

スクリプトをマスターページに追加

スクリプトを追加したら、忘れずにマスターページに追加します。jquery.mobileの前であればどこでもいいのですが、依存関係からしてServiceはViewModelの前に追加しておいたほうがいいでしょう。

<%@ Master Language="VB" AutoEventWireup="false" %>
<!DOCTYPE html>
<html>
<head runat="server">
    <title></title>
    <link type="text/css" rel="stylesheet" href="Content/jquery.mobile-1.1.0.min.css"/>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/jquery-1.7.2.min.js") %>'></script>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/knockout-2.1.0.js") %>'></script>
 <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/json2.min.js") %>'></script> <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/Service/CustomerService.js") %>'></script>     <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/ViewModel/FindCustomerViewModel.js") %>'></script>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/jquery.mobile-1.1.0.min.js") %>'></script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>

とりあえず呼び出してみよう

ViewModelでは、作成したモデルクラスをインスタンス化して呼び出すだけです。前回作ったViewModelにモデルのFindメソッドを呼び出すコードを追加します。

(function ($) {
    var viewModel = new (function () {
        var local = this;
        var service = new customerService();
        this.keyword = ko.observable("");

        this.find = function () {
            service.Find($, this.keyword(),
                function (result) {
                    var data = result.d;
                    alert(data.length);
                });
        };
    })();

    $(document).on("pageinit", "#FindCustomerView", function (event) {
        ko.applyBindings(viewModel, document.getElementById("FindCustomerView"));
    });
})($);

WCFをJSON形式の返却にした場合、dプロパティーの下にDataContractの内容が入ってきます。Fiddlerで、どんな文字列がHTTPに乗っているのかを確認して見ましょう。

image image

今回の例では、WCFから返却されたリストの件数をalert関数で表示しています。aspxをデバック実行して、検索ボタンをクリックしてみましょう。サービスの結果件数(3件)が表示されたのが確認できます。

image

次回はViewModelの更新とViewのリスト表示です。

過去へのリンクはこちらから

  • その1 はじめに
  • その2 ソリューション作成とライブラリの追加(knockout,jQuery,jQueryMobile)
  • その3 Knockoutを利用したViewModelの追加

Knockoutを利用したViewModelの追加

2012年6月5日 2件のコメント

WebFormでJavascript主体なスマートフォン向けサイトを作ろう その3

なんか間があいちゃいましたね。UIができたので、今回は業務ロジックとUIをつなぐViewModelを作成していきます。

Viewの変更

まずは画面の項目とJavascriptのバインディングをしておきましょう。前回のHTMLをこんな風に書き換えます。

<%@ Page Title="" MasterPageFile="~/Site.Master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <div data-role="page" id="FindCustomerView">
        <header data-role="header" data-position="fixed">
            <h1>顧客検索</h1>
        </header>
        <div data-role="content">
            <input type="text" data-bind="value: keyword"/>
            <input type="button" value="検索"

data-bind=”click: find”

 />
        </div>
    </div>
</asp:Content>

今回は検索キーワードをViewModelのkeywordプロパティーに、検索ボタンクリック時のイベントをViewModelのfindメソッドに割り当てています。

バインディングの詳細については、knockoutのドキュメントを確認しましょう。日本語の情報を探している場合は、このあたりが参考になります。そのうちちょこちょこ触れるかもしれません。

→ knockout.js 入門-鬼畜編<http://www.slideshare.net/shibayan/knockout-11523371>

 

ViewModelの追加と参照

続いてViewModel側の追加です。とりあえずView=ページとして作って置くと管理が楽そうなので、FindCustomerViewのViewModelは/Scripts/ViewMode/FindCustomerViewModel.jsとして作成しておきます。

image

続いて、追加したViewModelのJSファイルをマスターページに追加しておいてあげます(jQuery Mobileの場合は、ランディングページ以外は基本headerタグは読み込まれないので、利用するスクリプトはすべてマスターページに定義しておきます)。なんとなくViewModelの定義はknockoutの後、jQueryMobileの前に定義しています。

<%@ Master AutoEventWireup="false" %>
<!DOCTYPE html>
<html>
<head runat="server">
    <title></title>
    <link type="text/css" rel="stylesheet" href="Content/jquery.mobile-1.1.0.min.css"/>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/jquery-1.7.2.min.js") %>'></script>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/knockout-2.1.0.js") %>'></script>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/ViewModel/FindCustomerViewModel.js") %>'></script>
    <script type="text/javascript" src='<%= ResolveClientUrl("~/Scripts/jquery.mobile-1.1.0.min.js") %>'></script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>

マスターページ自体は今のところ、変わったところはありませんね。

ViewModelの定義

続いてViewModelの定義を行います。ViewModelには、検索キーワードとバインドするkeywordプロパティーと、検索ボタンがクリックされた際に呼び出されるfind関数を定義します。

(function ($) {
    var viewModel = new (function () {
        var local = this;
        this.keyword = ko.observable("");
        this.find = function () {
            //ToDo:サービスを呼び出してビジネスロジックを実行する。
            alert(local.keyword());
        };
    })();

    $(document).on("pageinit", "#FindCustomerView", function (event) {
        ko.applyBindings(viewModel, document.getElementById("FindCustomerView"));
    });
})($);
ViewModelでプロパティーの値を参照する場合は、ゲッター経由(関数呼び出し)なので注意しましょう。同じく設定する場合もセッター経由になります。

実行してみよう

この状態で実行すると、こうなります。

image

実行されましたか?

次回はjavascriptのモデルからWCFの呼び出しです。

ソリューション作成とライブラリの追加(knockout,jQuery,jQueryMobile)

2012年5月21日 3件のコメント

WebFormでJavascript主体なスマートフォン向けサイトを作ろう その2

と言うことで、まずはWebフォームのプロジェクトを作って、もろもろのプラグインたちを参照するマスターページを作りましょう。

プロジェクトの作成

まずは新規プロジェクトで、空のWebアプリケーションを作成します。名前はMobileTestとかにしておきましょうか。

image

必要なスクリプトの追加

次にjQueryやjQuery Mobile、Knockoutといったスクリプトたちをダウンロードして追加していきます。

Visual StudioのPackage Manager Consoleを開いてNugetからプロジェクトに追加します。

PM> install-package jquery
PM> install-package jquery.mobile
PM> install-package knockoutjs

マスターページの追加

jQuery Mobileでは、ユーザーが最初に開いたエントリーページ以降は、ページ遷移時にヘッダータグを読み飛ばすので、すべてのページには同じヘッダータグを記述して、スクリプトやCSSの読み込み漏れが起こらないようにします。

ASP.NET WebFormでは、マスターページを利用すると簡単です。

image

先程追加した、Javascriptファイルたちをマスターページに追加していきます。

<%@ Master Language="VB" AutoEventWireup="false" CodeBehind="Site.master.vb" Inherits="MobileTest.Site" %>
<!DOCTYPE html>
<html>
<head runat="server">
    <title></title>    <meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1"/>
    <link type="text/css" rel="stylesheet" href="~/Content/jquery.mobile-1.1.0.min.css"/>
    <script src='<%= ResolveClientUrl("~/Scripts/jquery-1.7.2.min.js") %>' type="text/javascript" ></script>
    <script src='<%= ResolveClientUrl("~/Scripts/knockout-2.1.0.js") %>' type="text/javascript" ></script>
    <script src='<%= ResolveClientUrl("~/Scripts/jquery.mobile-1.1.0.min.js") %>' type="text/javascript" ></script> 
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>

トップページの追加

次に最初に表示する画面(Top.aspx)を追加します。最初に表示する画面は、必要なスクリプト等を読み込んだSite.Masterをマスターページとして利用します。

image image

<%@ Page Title="" AutoEventWireup="false" MasterPageFile="~/Site.Master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <div data-role="page" id="FindCustomerView">
        <header data-role="header" data-position="fixed">
            <h1>顧客検索</h1>
        </header>
        <div data-role="content">
            <input type="text"/>
            <input type="button" value="検索" />
        </div>
    </div>
</asp:Content>

画面の表示

とりあえずVisual Studioのデバック実行で画面を表示してみましょう。

こんなふうに表示されましたか?

image

現在のソリューションの状況

こんな感じです。

image

次回はViewModelの追加です。