Knockout、jQuery、ASP.NET MVC 3を使用したTwitterライブ検索アプリケーションの開発

ユーザーが今日期待するレベルの応答、パフォーマンス、機能を備えた、適切に設計されたフロントエンドWebアプリケーションを開発することは簡単ではありません。 イベントハンドラー、HTMLマークアップ、およびAJAX呼び出しの沸騰したjQueryミックスでは迷子になりやすく、比較的単純なGUIでもすぐに維持するのが悪夢になります。



クライアント側で構造と順序を追加する1つの方法は、Knockoutのようなフレームワークを使用することです。 Knockoutは無料のオープンソースJavascriptライブラリであり、クライアントにModel-View-View Model(MVVM)パターンを実装するのに役立ちます。 十分に文書化されており、公式ウェブサイトは、ライブラリの組み込み機能の使用方法を示すだけでなく、独自の機能でそれを拡張する方法を示す実例の束の素晴らしい出発点です。



この投稿では、表示プラグイン、jQueryおよびASP.NET MVC 3バックエンド(または必要に応じてモデル)と組み合わせてKnockoutを使用して、Twitterでのライブ検索用のシンプルで効果的なアプリケーションを構築する方法について説明します。





目的



私たちの目標は簡単です。ユーザーは、検索条件(ハッシュタグやTwitterユーザー名など)を入力できる必要があり、その後、アプリケーションは対応する最も関連性の高いツイートを送信する必要があります。 また、クライアントのバックグラウンドプロシージャで多くの結果が自動的に更新されるため、GUIには常に見つかった最新のツイートが表示されます。 (これは、たとえば、現在および現在発生しているイベントを追跡する場合に役立ちます。)最終的に、次のようなものを取得したいと思います。





ステップ1:モデル定義



Twitterは、使用するのに十分単純で、検索クエリをXML(Atom)またはJSON形式で返すことができる検索APIを導入しています。 クライアントがTwitter APIと直接通信できるようにすることもできますが、これにより、キャッシュ、Twitterがクラッシュした場合のスタブなどを追加してアプリケーションを改善する機会が奪われます。 したがって、代わりに独自のモデルを作成することをお勧めします。このために、非常に単純なASP.NET MVC 3アプリケーションを使用します。



まず、標準の空のWebアプリケーション(表示エンジンとしてRazorを使用)を作成し、コントローラーを追加します-それをTwitterControllerと呼びましょう。 次に、新しいコントローラーで自動的に作成された「インデックス」アクションの名前を「検索」に変更します。 コントローラーは次のようになります。

public class TwitterController : Controller

{

[HttpGet]

public ActionResult Search()

{

return View();

}

}




* This source code was highlighted with Source Code Highlighter .






次に、Twitterで実際の検索を実行するアクションメソッドを作成します。 このタスクでは、検索APIのAtomバージョンを使用します。 リクエストURLは、次の形式のsearch.twitter.com/search.atom?q= [URL-encoded search parameters]に対応します 。 なぜなら AtomはXMLです。LINQto XMLを使用して、多くの結果を解析および変換できます(Twitter 必要のない多くのデータ返すため、最小限に削減します)。



しかし、XMLをクライアントに送信する必要はありません。より良いJSONです。 幸い、ほとんどのオブジェクトをJSONに変換するのは簡単です。この場合、最も簡単な方法は、JsonResultを返す組み込みのJsonメソッドを使用することです。 すべては次のとおりです。

[HttpPost]

public ActionResult Search( string query)

{

var atomResult = XDocument .Load( string .Format(

"http://search.twitter.com/search.atom?q={0}" ,

HttpUtility.UrlEncode(query)));

XNamespace ns = "http://www.w3.org/2005/Atom" ;

var searchResult =

from tweet in atomResult.Descendants(ns + "entry" )

let image = tweet.Elements(ns + "link" )

.Where(e => e.Attributes()

.Any(a => a.Name == "rel" &&

a.Value == "image" ))

.First(). Attribute ( "href" ).Value

let url = tweet.Elements(ns + "link" )

.Where(e => e.Attributes()

.Any(a => a.Name == "rel" &&

a.Value == "alternate" ))

.First(). Attribute ( "href" ).Value

select new

{

id = tweet.Element(ns + "id" ).Value,

author = tweet.Element(ns + "author" ).Element(ns + "name" ).Value,

imageUrl = image,

tweetUrl = url,

tweetText = tweet.Element(ns + "title" ).Value

};

return Json(searchResult);

}




* This source code was highlighted with Source Code Highlighter .






(上記のコードには、作成者のプロファイルでアバターを強調表示し、個々のツイートにリンクする解析手順が含まれています。)



それだけです-モデルを構築しました!



ステップ2:ビューモデルの実装



GUIの開発を開始する前に、ソリューションにいくつかのリンクを追加する必要があります。 NuGetを使用するか、jQuery、Knockout、jQuery.tmplを手動でロードします。 次に、「Search.cshtml」ビューをビュー/ Twitterに追加します(「マスターページ」やレイアウトを使用しないでください。ソリューションを多数の個別のファイルに分散しなければ、私たちと同様の小さなタスクで本質を簡単に把握できます)。 上記のJavascriptリンクを追加します。 これを行うと、次のようになります。

<! DOCTYPE html >

< html >

< head >

< meta charset ="utf-8" />

< title > Twitter Live Search </ title >

< script src ="@Url.Content(" ~/ Scripts / jquery-1 . 6 . 2 . js ")"

type ="text/javascript" ></ script >

<script src= "@Url.Content(" ~/Scripts/jquery.tmpl.min.js ")"

type= "text/javascript" ></script>

<script src= "@Url.Content(" ~/Scripts/knockout-1.2.1.js ")"

type= "text/javascript" > </ script >

</ head >

< body >

<!-- TODO -->

</ body >

</ html >




* This source code was highlighted with Source Code Highlighter .






それでは、ビューモデルを作成します。 ビューモデルには、クライアント側のアプリケーションロジックが含まれています。または、必要に応じて、マークアップ要素またはDOM要素に直接バインドせずに、アプリケーションが実行できることとそのプロパティを決定します。



このタスクの場合、ビューモデルは非常に単純です。現在の検索クエリと見つかったツイートを保存するために使用される2つのプロパティと、それに応じてモデルで検索を実行するメソッドが含まれています。 次のようになります。

<script type= "text/javascript" >

function SearchViewModel() {

this .query = ko.observable( '' );

this .tweets = ko.observableArray();

}



SearchViewModel.prototype.search = function () {

var q = this .query();

if (q.length > 0) {

$.ajax({

type: 'POST' ,

url: '/Twitter/Search' ,

data: { query: q },

dataType: 'json' ,

success: function (data) {

// TODO

}.bind( this )

});

} else {

// TODO

}

};

</script>




* This source code was highlighted with Source Code Highlighter .






ここに何か意味のあるものがあると言うのは難しいです。 requestおよびtweetプロパティは最初は空です。検索メソッドはjQueryを使用して、サーバー上のモデルにAJAXリクエストを送信し、結果をJSONオブジェクト(ツイートの配列)として返します。



検索メソッドに「成功した」ハンドラーをどのように実装する必要がありますか? ツイートの配列をクリアして、新しい検索結果を追加できます。 ただし、検索結果の「更新」を常に受け​​取りたいので、コレクション全体を置き換えずに新しいツイートを追加する(および古いツイートを削除する)のが理想的です。



これはKnockoutのマッピングプラグインを試す絶好の機会です。 ダウンロードしてスクリプトへのリンクを追加したら、成功したAJAXリクエストハンドラを実装できます。

success: function (data) {

ko.mapping.updateFromJS( this .tweets, data);

}.bind( this )




* This source code was highlighted with Source Code Highlighter .






そして、ツイートのコレクションに「 キー定義 」を設定します (これは、どの要素を追加、更新、または削除するかを決定するためにディスプレイで使用されます)。コンストラクターを少し書き換えます。

function SearchViewModel() {

this .query = ko.observable( '' );

this .tweets = ko.mapping.fromJS(

[],

{

key: function (tweet) { return ko.utils.unwrapObservable(tweet.id) }

});

}




* This source code was highlighted with Source Code Highlighter .






ツイートのコレクションのキーを、Twitterが便利に提供するID値として定義していることに注意してください。 Mappingプラグインの詳細については、Knockoutの公式Webサイトをご覧ください。



次:自動更新機能の実装。 検索クエリがあるたびに、たとえば3秒ごとに対応するツイートを更新して、モデルの変更を反映する必要があります。 これを達成する1つの方法は、再帰的であるが遅延した検索メソッドを呼び出すAJAX検索リクエストの成功したカルバックを作成することです。 この場合の完全なビューモデルは次のようになります。

<script type= "text/javascript" >

function SearchViewModel() {

this .query = ko.observable( '' );

this .tweets = ko.mapping.fromJS(

[],

{

key: function (tweet) { return ko.utils.unwrapObservable(tweet.id) }

});

this .autoRefreshId = null ;

}



SearchViewModel.prototype.search = function () {

var timeoutId = this .autoRefreshId;

if (timeoutId) {

window.clearTimeout(timeoutId);

this .autoRefreshId = null ;

}

var q = this .query();

if (q.length > 0) {

$.ajax({

type: 'POST' ,

url: '/Twitter/Search' ,

data: { query: q },

dataType: 'json' ,

success: function (data) {

ko.mapping.updateFromJS( this .tweets, data);

this .autoRefreshId = window.setTimeout(

this .search.bind( this ), 3000);

}.bind( this )

});

} else {

ko.mapping.updateFromJS( this .tweets, []);

}

};

</script>




* This source code was highlighted with Source Code Highlighter .






(検索クエリの入力行が空の場合に自動更新をオフにする行を追加しました。さらに、ユーザーが新しい検索を開始したときに実行中の検索を中断するチェックを追加しました。また、空のクエリを検索すると、検索結果は無効になります。)



ステップ3:デザインを表示する



物事をシンプルかつ明確に保つために、ビューは検索クエリの入力行とツイートのリストのみで構成されます。 この精神で何かを達成したいのです。

< form >

< input type ="search" placeholder ="Input #hashtag, @@username or something else" autofocus />

< input type ="submit" value ="Search" />

</ form >



< ul id ="tweets" >

< li >

< a href ="[url-of-tweet]" title ="[author-name]" >

< img src ="[url-of-author-image]" alt ="[author-name]" />

</ a >

< h6 > [author-name] </ h6 >

< p > [tweet-text] </ p >

</ li >

<!-- More tweets... -->

</ ul >




* This source code was highlighted with Source Code Highlighter .






また、ビューとビューモデルを接続する宣言的なKnockoutデータバインディングを追加しましょう。 検索フォームを少し変更すると...

< form data-bind ="submit: search" >

< input type ="search" data-bind ="value: query, valueUpdate: 'afterkeydown'" placeholder ="Input #hashtag, @@username or something else" autofocus />

< input type ="submit" value ="Search" />

</ form >




* This source code was highlighted with Source Code Highlighter .








... Knockoutは、ユーザーが検索クエリフィールドのテキストを変更すると、ビューモデルのクエリプロパティを自動的に更新し、ユーザーがEnterキーを押すとすぐに検索が実行されます。



検索結果はどうですか? Knockout テンプレートバインディングを使用する優れたスクリプト! まず、ツイートごとにテンプレートを作成します。

< script id ="tweetTemplate" type ="text/html" >

<li data-bind= "attr: { id: id }" >

<a data-bind= "attr: { href: tweetUrl, title: author }" >

<img data-bind= "attr: { src: imageUrl, alt: author }" />

</a>

<h6 data-bind= "text: author" ></h6>

<p data-bind= "text: tweetText" ></p>

</li>

</ script >




* This source code was highlighted with Source Code Highlighter .






次に、ビューモデル内のツイートのHTMLリストのdata-bindプロパティを使用して、各ツイートを表示する方法としてテンプレートを設定します。 比較的簡単:

< ul id ="tweets"

data-bind =" template: {

name: 'tweetTemplate' ,

foreach: tweets

}, visible: tweets (). length > 0" >

</ ul >




* This source code was highlighted with Source Code Highlighter .






(ビューモデルにツイートが含まれていない場合、リストは表示されないことに注意してください)



ボーナス: afterAddテンプレートバインドオプションを使用して、新しいツイートがリストに追加されるときに使用されるアニメーションを追加します。

< ul id ="tweets"

data-bind =" template: {

name: 'tweetTemplate' ,

foreach: tweets ,

afterAdd: function ( element ) {

$( element ). hide (). fadeIn ( 'fast' );

}

}, visible: tweets (). length > 0" >

</ ul >




* This source code was highlighted with Source Code Highlighter .






この時点で、やるべきことは、ブートストラップロジックだけです。 DOMが起動したら、ビューモデルをインスタンス化し、Knockoutにバインディングをアタッチするように依頼する必要があります。 jQueryドキュメントレディイベントハンドラーの1行のコード:

<script type= "text/javascript" >

$( function () {

ko.applyBindings( new SearchViewModel());

});

</script>




* This source code was highlighted with Source Code Highlighter .






できました! Windows 7マシンでChrome 12、Internet Explorer 9、Firefox 5でテストしました。完全なソリューションを次に示します(CSSを追加して、見栄えを悪くしました)。



All Articles