Knockout.jsの小ネタ
Knockout.jsでは通常、値をバインドしたい時は
<div data-bind="hoge">
このようにプロパティ名を指定します。
Knockout.jsには、とある条件の時にCSSクラスをバインドする機能があります。
例えばこんな感じに書きます。
<div data-bind="css: { css-no-class: foo() }">
このfooは、bool値を持つobservableだとします。
foo = ko.observable(true);
この時によくやってしまうのが
<div data-bind="css: { css-no-class: foo }">
fooが関数として実行されないというミス。
しかもJavaScriptは、この形でもtrueとして判断するので割と気づかない
falseにした時にあれれってなることが多いので注意が必要なのです。
訂正
コメントいただいて調べなおしたら上記はどうやら私の勘違いだったようです。
<div data-bind="css: { css-no-class: !foo }">
このパターンではうまく動かないと思っていたのですがちゃん動きました。
なんで動かなかったんだろう???
関数呼び出しをしなければいけないパターンは
<div data-bind="css: { css-no-class: count() < 10 }">
こんな感じで比較を行った場合でした。
Chutzpahを使ったTypeScriptのテストで困ったこと
VisualStudioでJavaScriptの単体テストもやってくれるようにするアドインのChutzpahですが
TypeScriptを使ったプロジェクトだといくつか困った問題が発生します。
こんなテストが有ったとします。
JavaScriptではなくTypeScriptで書いてます。
(この例だと分かりづらいですけど・・・)
/// <reference path="typings/jquery/jquery.d.ts" /> /// <reference path="typings/jasmine/jasmine.d.ts" /> describe("test_", () => { it("hoge", () => { spyOn($, "ajax").andCallFake( function (_) { var d = $.Deferred(); d.resolve([ { id: 1, name: "佐藤" }, { id: 2, name: "鈴木" } ]); return d.promise(); });; // なんかテスト }); });
これをテストエクスプローラで見ると
こんな感じで1つのテストが3つに見えてしまいます。
しかも1つは文字化けしてます。
1つは、WebEssentialsというアドインがTypeScriptをコンパイルした時に
生成されるminifyの方もテスト対象になってしまっているからです。
ASP.NET MVCの場合は、minifyは必要ないのでこれは生成されないように設定を変更します。
[ツール]→[オプション]から[Web Essentials]を選択し[Minify generated JavaScript]をfalseにします。
※既に出来てしまっているminifyファイルは削除してください。
もう1つが分かりにくかったのですが、Chutzpahは生成されたJavaScriptではなくTypeScriptでもテストが出来るようで
JavaScriptとTypeScriptのどちらもテストをしてしまっています。
これを設定でJavaScriptだけにします。(TypeScriptの方は文字化けしてしまっている方なので使いません)
[ツール]→[オプション]から[Chutzpah]を選択し[Testing Mode]をJavaScriptにします。
これで1つになりました。
実はもう1つ困ったことが起こるんです。
このテストを実行するとこんな感じでエラーになります。
$という変数が無いと言ってますね
TypeScript的な参照は1行目で行ってますが
生成されたJavaScriptにはjQueryのJavaScriptファイルがどこにあるのか分かりません。
jQueryのJavaScriptファイルを参照できるように1行目に追記します。
普通のrefernceだとコンパイルエラーになるので注意です。
/// <chutzpah_reference path="jquery-2.0.3.js" /> /// <reference path="typings/jquery/jquery.d.ts" /> /// <reference path="typings/jasmine/jasmine.d.ts" />
これでテストが成功します。
TFSのwiqlではまったこと
TFSの作業項目をプロジェクト横断的に取得したくて
ここ見て作ってたら見事の嵌められたのでメモっておきます。
例に倣ってこんな感じで作ります。
var tpc = new TfsTeamProjectCollection( new Uri("http://localhost:8080/tfs/DefaultCollection")); var workItemStore = (WorkItemStore)tpc.GetService(typeof(WorkItemStore)); var queryResults = workItemStore.Query("Select [State], [Title] From WorkItems Where [Work Item Type] = 'User Story' Order By [State] Asc, [Changed Date] Desc");
これを実行すると
Stateが無いとかエラーが出ます。絶対にあるのに!!
なんだかんだ色々試した結果
var tpc = new TfsTeamProjectCollection( new Uri("http://localhost:8080/tfs/DefaultCollection")); var workItemStore = (WorkItemStore)tpc.GetService(typeof(WorkItemStore)); var queryResults = workItemStore.Query("Select [System.State], [System.Title] From WorkItems");
カラム名の前にSystem.を付けるとちゃんとデータが取得できる!
でもカラム名に半角スペース付いているとエラーになる! まだ回避方法がわからん
でも今、作っているプログラムは半角スペースがあるカラムは必要ないので掘り下げないかもね
ASP.NET MVCでJSONのプロパティをLowerCaseで返す方法
ASP.NET MVCでアプリケーションを作成しているときに
ちょっと困るのがAJAXでオブジェクトを取得したときに
プロパティがUpperCaseで返ってくることです。JavaScriptではLowerCaseで扱いたい><
今まではしょうがないって思ってたんですけどちょうどJavaScriptのリファクタリングをする必要があったので
C#側でLowerCaseで返すようにしてみました。
こんな感じのメソッドがあるとします。
クラスはMVCのControllerクラスを継承してAppControllerクラスを継承しています。
public class HomeController : AppController { public ActionResult GetData() { var model = new Model { ID = 1, Name = "佐藤" }; return Json(model, JsonRequestBehavior.AllowGet); } }
通常はこんな感じでそのまま頭大文字でJSONが返ります。
{"ID":1,"Name":"佐藤"}
頭を小文字に変更します。
まずMVCのJsonResultクラスを継承したAppJsonResultクラスを作成し
ExecuteResultメソッドをオーバーライドします。
ほとんどMVCのメソッドまるパクリなんですけどJSON文字列を生成するところだけ変更しています。
JSONの生成にはJson.NETを利用します。
public class AppJsonResult : System.Web.Mvc.JsonResult { public override void ExecuteResult(ControllerContext context) { if (context == null) { throw new ArgumentNullException("context"); } HttpResponseBase response = context.HttpContext.Response; if (!String.IsNullOrEmpty(ContentType)) { response.ContentType = ContentType; } else { response.ContentType = "application/json"; } if (ContentEncoding != null) { response.ContentEncoding = ContentEncoding; } if (Data != null) { var json = JsonConvert.SerializeObject( Data, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() } ); response.Write(json); } } }
AppControllerクラスでJsonResultメソッドをオーバーライドしてAppJsonResultを返すようにします。
public class AppController : Controller { protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior) { return new AppJsonResult { Data = data, ContentType = contentType, ContentEncoding = contentEncoding, JsonRequestBehavior = behavior }; } }
これでLowerCaseになったJSONを返すことができました。
{ "id": 1, "name": "佐藤" }
APIフレームワークだともっと簡単にできるみたいなんですけど
MVCだとなんかいい方法が見つからなかったんでこんな方法にしてみました。
まあこれから作るんだったらAPIの方で作れってことですね。
jQuery.ajaxで配列を送信するのに嵌った
jQueryのajaxメソッドを使って配列をサーバに送信するのに嵌ったのでメモ
サーバサイドは、ASP.NET MVCです。
まずサーバサイドのコード
[HttpPost] public ActionResult Post(string[] values) { return View(); }
引数で文字列の配列を取ります。
予定では、モデルバインダーで自動的にvaluesに値が入るはずです。
で、問題のJavaScriptのコード
$(function () { $.ajax({ url: "Home/Post", type: "POST", datatype: "json", data: { values: ["a", "b"] }, }); });
これを実行すると
valuesはnullです。
バインドが出来ていませんね
Resuestの中身を見てみると
なんかパラメータ名に変なの付いてる!
実はこれ大かっこなんです。
jQueryのやつが勝手に大かっこなんて付けやがるんですね
ASP.NET MVC的には大迷惑です。
でも回避方法がありました。
$(function () { $.ajax({ url: "Home/Post", type: "POST", datatype: "json", data: { values: ["a", "b"] }, traditional: true, }); });
ajaxメソッドのオプションに
traditional: true
を追加します。
すると
今度はちゃんと値が入っています。
まああんまりこんな感じで配列を送りたい時がそうそう無いんですけどね
mongoDBにバイナリデータを登録する
ひさしぶりにmongoDBネタで
mongoDBに画像データを登録したかったのですが
C#から実行する方法があまり情報が無かったのでメモっておきます。
まあ流れ的にはSQLServerとか他のDBと同じみたいですね。
(自分はバイナリデータをDBに登録するとか経験ないんですけどそうみたいです)
めんどいので適当に
var imageStream = new FileStream(@"sample.png", FileMode.Open, FileAccess.Read); // streamからbyte配列を作成 var imageData = new byte[imageStream.Length]; imageStream.Read( imageData, 0, Convert.ToInt32( imageStream.Length ) ); // byte配列を持つモデル model.Image = imageData; // mongoDBに更新する処理 ・・・
てな感じでバイナリデータをmongoDBに登録することができます。
TFSビルドプロセスの小ネタ
TFSでビルドプロセスを作成していると引数や変数の値が知りたい時があります。
でも通常の設定だと確認することができません。
じゃーどうするかっていうと
ビルド定義の編集から「プロセス」を選択して
「ログの詳細度」を「Diagnostic」に変更します。
するとこんな感じでパラメータの値がログに出力されます。
上図は、初期値ですが変更されたりした場合もすべて表示されます。