Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

JsRenderチュートリアル - 存在しないプロパティを参照した時のエラーを回避する

JavaScript製でjQuery非依存なテンプレートエンジンであるJsRender/JsViewsを使ったチュートリアルを書いてみようと思います。
以前に書いたエントリJsRender入門 - Do You PHP はてなも参照してください。

今回やること

JsRenderやJsViewsで存在しないプロパティを参照した時のエラーを回避する

コード

<html>
<body>

<!-- レンダリング結果を表示するスペース -->
<div id="result"></div>

<script src="https://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="http://www.jsviews.com/download/jsviews.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
    // データの配列(もしくはオブジェクト)
    var fruits = {
            code: "01",
            name: "りんご",
            color: {
                name: "赤"
            },
            err: function() {
                return "エラーです";
            }
        };

    $.views.helpers({
        onerror: function(message) {
            return message + "です";
        }
    });

    // テンプレートに名前をつけて登録する
    $.templates({
        fruitsTemplate: "#template"
    });

    // テンプレート"fruitsTemplate"に変数fruitsを渡し、
    // レンダリング結果をid="result"に表示
    $("#result").html($.render.fruitsTemplate(fruits));
});
</script>

<script id="template" type="text/x-jsrender">
    <div>
        <li>{{>color.name}}</li>

        {{!--
            存在するオブジェクトのundefinedなプロパティを参照しても
            エラーにならず、空文字が表示される
        --}}
        <li>{{>color.foo}}</li>

        {{!--
            #data直下のundefinedなプロパティを参照してもエラーにならず、
            空文字が表示される
        --}}
        <li>{{>foo}}</li>

        {{!--
            undefinedのプロパティを参照すると

              {Error: TypeError: data.color.foo is undefined}

            というエラーになるが、onerrorを使うとエラー時に表示する
            メッセージを指定できる
        --}}
        <li>{{>color.foo.bar onerror="barがありません"}}</li>

        {{!-- リテラルだけではなくリンクした変数やヘルパーも使える --}}
        <li>{{>color.foo.bar onerror=color.name + "です"}}</li>
        <li>{{>color.foo.bar onerror=err()}}</li>
        <li>{{>color.foo.bar onerror=~onerror("ヘルパー")}}</li>
    </div>
</script>
</body>
</html>

説明

JsRenderやJsViewsで存在しないプロパティを参照した場合、

{Error: TypeError: data.foo.bar is undefined}

のようなメッセージが表示されることがありますが、このデフォルトのメッセージではなく任意のメッセージを表示させることができます。
JsRenderでの書式は次のとおりで、変数や式に続けて"onerror="と表示するメッセージを記述します。

{{>[変数や式] onerror=[表示するメッセージ]}}

表示するメッセージには、文字列のほか、テンプレートに渡された変数の値やヘルパーも使用できます。
JsViewsの場合、データリンクしたタグ({^{...}})のほかにdata-link属性にも記述可能です。

<li data-link="color.foo.bar onerror='エラーです'"></li>

JSFiddleで動作を見る

JsViewsチュートリアル - スタイルをリンクさせる

JavaScript製でjQuery非依存なテンプレートエンジンであるJsRender/JsViewsを使ったチュートリアルを書いてみようと思います。
以前に書いたエントリJsViews入門 - Do You PHP はてなも参照してください。

今回やること

JsViewsでスタイルと変数をリンクさせる

コード

<html>
<body>

<!-- レンダリング結果を表示するスペース -->
<div id="result"></div>

<style type="text/css">
<!--
.box {
    border: 1px solid;
    display: table-cell;
    text-align: center;
    vertical-align: middle;
}
-->
</style>
<script src="https://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="http://www.jsviews.com/download/jsviews.min.js" type="text/javascript"></script>
<script type="text/javascript">
// スタイルのリンク
$(function() {
    // 表示するデータ
    var data = {
        text: 'Hello !',
        width: 150,
        height: 100,
        bgcolor: 'lightgray'
    };

    // テンプレートに名前(ここでは"linkTemplate")をつけて登録する
    $.templates({
        linkTemplate: "#template"
    });

    // テンプレート"linkTemplate"と変数dataをリンク
    $.link.linkTemplate('#result', data);
});
</script>

<!-- テンプレート -->
<script id="template" type="text/x-jsrender">
    <div class="box" data-link="
        {:text}
        css-color{:bgcolor != '' ? 'white' : ''}
        css-background-color{:bgcolor}
        css-width{:width}
        css-height{:height}"
    >
    </div>
    <div>
        <p>表示するテキスト</p>
        <input type="text" data-link="text trigger=true"/>
    </div>
    <div>
        <p>幅</p>
        <select data-link="width">
        <option value="100">100</option>
        <option value="150">150</option>
        <option value="200">200</option>
        </select>
    </div>
    <div>
        <p>高さ</p>
        <select data-link="height">
        <option value="100">100</option>
        <option value="150">150</option>
        <option value="200">200</option>
        </select>
    </div>
    <div>
        <p>背景色</p>
        <select data-link="bgcolor">
        <option value="">なし</option>
        <option value="lightgray">lightgray</option>
        <option value="blue">blue</option>
        <option value="red">red</option>
        <option value="green">green</option>
        </select>
    </div>
</script>
</body>
</html>

説明

JsViewsチュートリアル - HTML要素の属性をデータリンクする - Do You PHP はてなでは属性と変数をリンクさせましたが、スタイルと直接リンクさせる事もできます。
書式ですが、属性名の代わりにプロパティ名に"css-"を付けたものになります。

data-link="css-[プロパティ名]{:[変数もしくは式]}

たとえば、colorプロパティであれば"css-color"、background-colorプロパティであれば"css-background-color"になります。
コード例では、

  • width
  • height
  • background-color

の3つを変数と直接リンクさせ、colorプロパティについてはbackground-colorプロパティの値が指定された場合に"white"となるように記述しています。

JSFiddleで動作を見る

JsViewsチュートリアル - HTML要素の属性値のトグル

JavaScript製でjQuery非依存なテンプレートエンジンであるJsRender/JsViewsを使ったチュートリアルを書いてみようと思います。
以前に書いたエントリJsViews入門 - Do You PHP はてなも参照してください。

今回やること

JsViewsでHTML要素の属性値をデータリンクさせた変数の値を使ってトグルさせる

コード

<html>
<body>

<!-- レンダリング結果を表示するスペース -->
<div id="result"></div>

<style type="text/css">
<!--
.label { font-weight: bold; }
.red { color: #e03fac; }
-->
</style>
<script src="https://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="http://www.jsviews.com/download/jsviews.min.js" type="text/javascript"></script>
<script type="text/javascript">
// 属性のトグル
$(function() {
    // 表示するデータ
    var data = {
        mode: '1'
    };

    // テンプレートに名前(ここでは"linkTemplate")をつけて登録する
    $.templates({
        linkTemplate: "#template"
    });

    // テンプレート"linkTemplate"と変数dataをリンク
    $.link.linkTemplate('#result', data);
});
</script>

<!-- テンプレート -->
<script id="template" type="text/x-jsrender">
    <div>
        <p>現在のmode:<span data-link="mode"></span></p>
        <label for="mode1">
            <input type="radio" id="mode1" name="radio" value="1" data-link="mode"/>
            <span class="label" data-link="class{merge:mode == '1' toggle='red'}">ラジオ1</span>
        </label>
        <label for="mode2">
            <input type="radio" id="mode2" name="radio" value="2" data-link="mode"/>
            <span class="label" data-link="class{merge:mode == '2' toggle='red'}">ラジオ2</span>
        </label>
        <label for="mode3">
            <input type="radio" id="mode3" name="radio" value="3" data-link="mode"/>
            <span class="label" data-link="class{merge:mode == '3' toggle='red'}">ラジオ3</span>
        </label>
    </div>
</script>
</body>
</html>

説明

JsViewsチュートリアル - HTML要素の属性をデータリンクする - Do You PHP はてなでは属性値そのものををデータリンクした変数とリンクさせましたが、「変数が○○○の時だけ特定の属性を追加する」といった属性の値の一部をトグルさせる事もできます。
書式ですが、mergeコンバータを使って次のようになります。

data-link="[属性名]{merge:[変数もしくは式] toggle='[トグルさせる値]'}

変数もしくは式がtrueと判定された場合に限り、指定した属性名に"トグルさせる値"が追加されます。それ以外の場合は追加されません。
たとえば、「特定の場合だけclass属性に"active"というクラスを追加する」といった感じです。コード例では、ラジオボタンが選択された場合のみラベルに色を付けています。
なお、最初から指定されていた属性値はtoggleによる影響を受けません。コード例の場合だと、"label"クラスは上書きされずに残ります。

JSFiddleで動作を見る

JsViewsチュートリアル - データリンクの方向性

JavaScript製でjQuery非依存なテンプレートエンジンであるJsRender/JsViewsを使ったチュートリアルを書いてみようと思います。
以前に書いたエントリJsViews入門 - Do You PHP はてなも参照してください。

今回やること

JsViewsのデータリンクが一方向・双方向の2種類あることを確認する

コード

<html>
<body>

<!-- レンダリング結果を表示するスペース -->
<div id="result"></div>

<script src="https://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="http://www.jsviews.com/download/jsviews.min.js" type="text/javascript"></script>
<script type="text/javascript">
// データリンクの方向性
$(function() {
    // 表示するデータ
    var message = {
        greet: 'Hello !'
    };

    // テンプレートに名前(ここでは"linkTemplate")をつけて登録する
    $.templates({
        linkTemplate: "#template"
    });

    // テンプレート"linkTemplate"と変数messageをリンク
    $.link.linkTemplate('#result', message);
});
</script>

<!-- テンプレート -->
<script id="template" type="text/x-jsrender">
    <div>
        <p><span data-link="greet"></span></p>

        {{!-- 変数名(triggerを含む)の前にのみ":"を付けた場合は一方向リンク --}}
        <p>一方向:data-link="{:greet trigger=true}"</p>
        <div><input data-link="{:greet trigger=true}"/></div>

        {{!-- 変数名(triggerを含む)の前後に":"を付けた場合は双方向リンク --}}
        <p>双方向:data-link="{:greet trigger=true:}"</p>
        <div><input data-link="{:greet trigger=true:}"/></div>

        {{!-- 変数名(triggerを含む)だけの場合は1番目の記述方法の省略形(双方向リンク) --}}
        <p>双方向:data-link="greet trigger=true"</p>
        <div><input data-link="greet trigger=true"/></div>
    </div>
</script>
</body>
</html>

説明

JsViewsチュートリアル - フォーム要素とデータリンク(チェックボックス+コンバータ) - Do You PHP はてなでも軽く触れましたが、JsViewsのdata-link属性に変数を記述する際、記述方法によって変更した値をリンクした変数に反映するかどうかが決まります。
JsViewsでのデータの流れは、先のエントリでも若干説明しましたが、大まかに以下のようになります。

変数 → [値] → [コンバータによる変換] → data-link属性を付けたHTML要素 → [変更された値] → [コンバータによる変換] → 変数

一方、data-link属性の値は、正しくは先のエントリにある

data-link="{[変数を取得する際のコンバータ]:[変数名]:[変数を書込む際のコンバータ]}"

という記述方法になります。各コンバータは省略可能です。先ほどのデータの流れに対応してるのが分かりますかね?
また、変数とコンバータの区切りに":"(コロン)を付けていますが、これが"どの方向に対してデータをリンクするか"を表しています。たとえば、上のように変数名の前後に":"を付けると、データの流れが

  • 変数→HTML要素
  • 変数←HTML要素

という双方向になります。これは双方向(two-way)データリンクと呼ばれます。
一方、後ろの":"以降を省略すると

data-link="{[コンバータA]:[変数名]}"

となりますが、データの流れは

変数 → [値] → [コンバータAによる変換] → data-link属性を付けたHTML要素

という具合に

  • 変数→HTML要素

という流れのみになるので、一方向(one-way)データリンクと呼ばれます。結果として、変更した値は変数に反映されません
また、

data-link="{:[変数名]:}"

とすれば

変数 → [値] → data-link属性を付けたHTML要素 → [変更された値] → 変数

になりますが、これは今までの説明で出てきた

data-link="[変数名]"

と等価になります。
なお、変数名の前の":"のみ省略する、ということはできません。

ちなみに、フォーム要素以外のHTML要素の場合、リンクされた値を直接変更する手段がありませんので、一方向・双方向のいずれの記述方法でも結果的に一方向となります。

JSFiddleで動作を見る

JsViewsチュートリアル - HTML要素の属性をデータリンクする

JavaScript製でjQuery非依存なテンプレートエンジンであるJsRender/JsViewsを使ったチュートリアルを書いてみようと思います。
以前に書いたエントリJsViews入門 - Do You PHP はてなも参照してください。

今回やること

JsViewsでHTML要素の属性をデータリンクさせる

コード

<html>
<body>

<!-- レンダリング結果を表示するスペース -->
<p>テキストボックスに入力すると表示されたデータが更新される</p>
<div id="result"></div>

<style type="text/css">
<!--
.green { color: #3fe0ac; }
-->
</style>
<script src="https://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="http://www.jsviews.com/download/jsviews.min.js" type="text/javascript"></script>
<script type="text/javascript">
// 属性をリンクさせる
$(function() {
    // 表示するデータ
    var message = {
        greet: 'Hello !',
        color: 'green',
        type: 'password',
        id: 'message',
        multiple: true
    };

    // テンプレートに名前(ここでは"linkTemplate")をつけて登録する
    $.templates({
        linkTemplate: "#template"
    });

    // テンプレート"linkTemplate"と変数messageをリンク
    $.link.linkTemplate('#result', message);
});
</script>

<!-- テンプレート -->
<script id="template" type="text/x-jsrender">
    <div>
        <p><span data-link="{:greet} class{:color}"></span></p>
        <div><input data-link="{:greet trigger=true} type{:type} id{:id}"/></div>

        <select id="select" data-link="multiple{:multiple}">
        <option value="1">セレクト1</option>
        <option value="2">セレクト2</option>
        <option value="3">セレクト3</option>
        </select>
    </div>
</script>
</body>
</html>

説明

1つ前のエントリと同様、JsViewsではフォーム要素のvalue値や可視性(visibility)だけではなく、classやtype、idなど他のHTML属性ともリンクさせることができます。
書式は次のようになります。1つ前のエントリの一般形ですね。

<[HTML要素名] ... data-link="[属性名]{:[変数もしくは式]} ..." />

また、以下のように複数同時に設定することも可能です。1つ前のエントリにあるvisibleも同様です。

<div data-link="id{:id} class{:color} visible{:visibility}">...</div>

ただし、"input要素のvalue属性の値と、他の属性値を同時に指定したい"といった場合、前者の書き方を以下のようにする必要があります。

{:[変数名]:}

これを

{:[変数名]}

としてしまうと、フォーム要素で変更した値がリンクした変数に反映されません。一方、span要素やdiv要素など、値を変更することができない要素の場合はいずれの記述でも問題ありません。

JSFiddleで動作を見る

JsViewsチュートリアル - visibilityをリンクする

JavaScript製でjQuery非依存なテンプレートエンジンであるJsRender/JsViewsを使ったチュートリアルを書いてみようと思います。
以前に書いたエントリJsViews入門 - Do You PHP はてなも参照してください。

今回やること

JsViewsで変数の値と可視性(visibility)をリンクさせる

コード

<html>
<body>

<!-- レンダリング結果を表示するスペース -->
<p>テキストボックスに入力すると表示されたデータが更新される</p>
<div id="result"></div>

<script src="https://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="http://www.jsviews.com/download/jsviews.min.js" type="text/javascript"></script>
<script type="text/javascript">
// visibilityをリンクさせる
$(function() {
    // 表示するデータ
    var message = {
        greet: 'Hello !'
    };

    // テンプレートに名前(ここでは"linkTemplate")をつけて登録する
    $.templates({
        linkTemplate: "#template"
    });

    // テンプレート"linkTemplate"と変数messageをリンク
    $.link.linkTemplate('#result', message);
});
</script>

<!-- テンプレート -->
<script id="template" type="text/x-jsrender">
    <div>
        <p><span class="red" data-link="visible{:greet == 'Hello'}">"Hello"以外を入力してください</span></p>
        <div><input type="text" data-link="greet trigger=true"/></div>
    </div></script>
</body>
</html>

説明

JsViewsではフォーム要素のvalue値だけではなく、可視性(visibility)とリンクさせることができます。
書式は次のようになります。

<[HTML要素名] ... data-link="visibile{:[変数もしくは式]}" />

JSFiddleで動作を見る

JsViewsチュートリアル - フォーム要素とデータリンク(チェックボックス+コンバータでvalue属性の値を使う)

JavaScript製でjQuery非依存なテンプレートエンジンであるJsRender/JsViewsを使ったチュートリアルを書いてみようと思います。
以前に書いたエントリJsViews入門 - Do You PHP はてなも参照してください。

今回やること

JsViewsでチェックボックスをデータリンクさせ、コンバータで変数に格納する値をvalue属性の値に変更する

コード

<html>
<body>

<!-- レンダリング結果を表示するスペース -->
<div id="result"></div>

<script src="https://code.jquery.com/jquery-1.11.1.min.js" type="text/javascript"></script>
<script src="http://www.jsviews.com/download/jsviews.min.js" type="text/javascript"></script>
<script type="text/javascript">
// フォーム要素とデータリンク
$(function() {
    $.views.converters({
        preCheckboxWithValue: function (value) {
//            console.log(this);
            var v = this.linkCtx.elem.value ? this.linkCtx.elem.value : null;
            return value === v ? true : false;
        },
        postCheckboxWithValue: function (value) {
//            console.log(this);
            var v = this.linkCtx.elem.value ? this.linkCtx.elem.value : null;
            return value == true ? v : null;
        }
    });

    // 表示するデータ
    var message = {
        check_as_value: null
    };

    // テンプレートに名前(ここでは"linkTemplate")をつけて登録する
    $.templates({
        linkTemplate: "#template"
    });

    // テンプレート"linkTemplate"と変数messageをリンク
    $.link.linkTemplate('#result', message);
});
</script>

<!-- テンプレート -->
<script id="template" type="text/x-jsrender">
    <p>check_as_value=<span data-link="check_as_value"></span></p>

    <div>
        <label for="check_as_value"><input id="check_as_value" type="checkbox" value="bar" data-link="{preCheckboxWithValue:check_as_value:postCheckboxWithValue}"/>チェックボックス</label>
    </div>
</script>
</body>
</html>

説明

1つ前のエントリではコンバータを使ってチェックボックスとデータリンクさせた場合の値を"0"と"1"に変換する例を見てきましたが、どうせならチェックボックスvalue属性の値にしたいですよね?
コンバータとして定義した関数内では、自身を表す"this"を使って現在対象となっている要素やViewオブジェクトなどの"コンテキスト情報"を取得することができます。
たとえば、現在のコンバータが対象としている変数はtagCtx(タグコンテキスト)を使って

this.tagCtx.params.args

その値は

this.tagCtx.args

また、リンクされた変数の値は

this.linkCtx._val

といった具合です。実際にコンバータ関数の中でconsole.log()等で値を確認してみると良いです。
で、この中に、現在コンバータが対象としているHTML要素も

this.linkCtx.elem

で取得でき、そのvalue属性の値を

this.linkCtx.elem.value

で参照できます。これを使うことでvalue属性の値を結果の値とすることができます。

JSFiddleで動作を見る