LoginSignup
0
0

More than 5 years have passed since last update.

【Fuse】EachでObservableなButtonをつくる

Posted at

今回はこちらのページに沿って進めていきます。

イントロ

前回の記事では、静的なテキストの表示など基礎的なところから、入力フィールドを追加して、変更を伝達させるなどを行いました。今回はいくつかのハイキング情報を作成、選択、編集できるようにしてみたいと思います。

このチュートリアルでは、管理が楽になるよう、MainView.uxに全ての情報を保存します。ビューの上部にセレクターを追加して、編集したいハイキングを選択し、前回のビューにこのデータを入力しましょう。

※この段階ではまだ変更は保持されません。モデルのデータをビューに適用するだけですので、起動時にリセットされます。しかし、後の章でそれを解決する予定です。

ハイキングのリストのデータを作る

ハイキングのリストを表示するには、そのデータが必要なので、アプリのモデルのようなものを構築します。まずは単純な配列でつくってみます。JSに次のデータを追加します。


var _hikes = [
    {
        id: 0,
        name: "Tricky Trails",
        location: "Lakebed, Utah",
        distance: 10.4,
        rating: 4,
        comments: "This hike was nice and hike-like. Glad I didn't bring a bike."
    },
    {
        id: 1,
        name: "Mondo Mountains",
        location: "Black Hills, South Dakota",
        distance: 20.86,
        rating: 3,
        comments: "Not the best, but would probably do again. Note to self: don't forget the sandwiches next time."
    },
    {
        id: 2,
        name: "Pesky Peaks",
        location: "Bergenhagen, Norway",
        distance: 8.2,
        rating: 5,
        comments: "Short but SO sweet!!"
    },
    {
        id: 3,
        name: "Rad Rivers",
        location: "Moriyama, Japan",
        distance: 12.3,
        rating: 4,
        comments: "Took my time with this one. Great view!"
    },
    {
        id: 4,
        name: "Dangerous Dirt",
        location: "Cactus, Arizona",
        distance: 19.34,
        rating: 2,
        comments: "Too long, too hot. Also that snakebite wasn't very fun."
    }
];

各アイテムが同じフィールドを持っています。IDは一意の識別子です。

※各変数のスコープですが、基本的には同一の<JavaScript>でないとデータにはアクセスできないようです。なので、必要なデータは同じ<JavaScript>内に含めるように配置してください。

ハイキングリストを表示しよう

データはできたので、それを表示するビューを作りましょう。まずは作ったデータをmodule.exportsに含めるところからです。

module.exports = {
    hikes: _hikes,
    name: _name,
    location: _location,
    distance: _distance,
    rating: _rating,
    comments: _comments
}

ハイキングを選択できるようにするため、それぞれのボタンを表示します。押されたらそのハイキングの編集ビューが表示されるようにします。データの数に応じてボタンが作られるようにしたいので、下記のようにします。

MainView.ux
<Each Items="{hikes}">
</Each>

<Each>はとても強力な機能です。<Each>itemsプロパティで指定されたコレクションを取得し、各アイテムを各タグの中のサブツリーのコピーに渡します。<Each>の中に、各アイテムをコピペするような感じです。

ここでは、ハイキングの名前がセットされたボタンを<Each>を使って作成します。

MainView.ux
<Each Items="{hikes}">
    <Button Text="{name}" />
</Each>

これを<StackPanel>の一番上にセットすれば、各アイテムのnameがテキストとしてセットされたボタンが完成します。当然、<Each>を複数配置すればその分ボタンは生成されます。<JavaScript>側では、データを丸ごと公開だけである(nameという属性は公開していない)ことに注目してください。exportされた要素の中にnameというプロパティが既にありますが、<Each>は、hikesに自動的にコンテキストを絞り込んでくれます。なので、意図したnameをバインドしてくれます。

01.png

ハイキングを選択する

さて、ボタンを作ることができたので、クリックして選択しましょう。現状のビューは編集可能な複数のObservableで構成されています。そこに、現在編集しているハイキングを表すObservableを追加します。デフォルトの値は空にしておきます。

var hike = Observable();

今度は、今作ったObservableから、他のObservableにデータを渡す必要があります。片方は、ハイキングが行われるたびにObservableなフィールドを追加しないといけないので、もうちょっと綺麗に書きたいところです。

そこで、mapメソッドを使ってObservableを複製します。

var name = hike.map(function(x) { return x.name; });

リアクティブプログラミングに慣れていないときは、少し気になるかもしれませんが、心配しないでください。深く考えず、直感的に見てもらえば大丈夫です。

このコードを分解してみると、まず、hikemapを実行しています。mapは、新しいObservableを返します。そのObservableの中に入る各値は、hikeの中の各値が伝搬されています。つまり、新しく作られたObservableは、hikeの中にある値からマップされ、hikeの値に基づいています。

また、渡している関数はマッピング関数とよばれ、引数を一つとり、その引数に基づいた値を返します。場合によっては、他のコードに影響を与えてしまう場合もありますが、基本的にはpure関数なので、値が変わることはありません。

簡単にいえば、ハイキングに新しい値が追加されても、逐一Observableを加えなくていいということです!Modelに追加しておけば、自動的に引数として渡されます。map関数は、その渡された引数に基づいて新しい値を返します。この値がObservableの値となります。

Observableについては、Observable Crash Courseリファレンスで詳細を調べることができます。

さて、それでは、nameと同じように、ほかのものもリファクタリングしましょう。

MainView.ux
var name = hike.map(function(x) { return x.name; });
var location = hike.map(function(x) { return x.location; });
var distance = hike.map(function(x) { return x.distance; });
var rating = hike.map(function(x) { return x.rating; });
var comments = hike.map(function(x) { return x.comments; });

最後に、各ボタンと、クリックしたときに、実行する関数を繋げる必要があります。まず、空の関数を作り、exportに追加します。

function chooseHike() {
}

module.exports = {
    hikes: _hikes,
    name: _name,
    location: _location,
    distance: _distance,
    rating: _rating,
    comments: _comments,
    chooseHike: chooseHike
};

ボタンとこの関数を紐付けます。

<Button Text="{name}" Clicked="{chooseHike}" />

これであとは関数の中身を作っていくだけです。Observableの値を指定したいのですが、どうすればよいでしょう?ButtonのClickedに関数をバインドしたので、引数として、<Each>でまわしているデータのコンテキストを表すデータフィールドが渡されます。そのデータをとって、渡しましょう。

function chooseHike(_item) {
    hike.value = _item.data;
}

保存すれば、期待通り動作していると思います。最初は空だった入力フィールドが、ハイキングを選択するとそれぞれのデータで埋められます。

今日の成果はこんな感じです!

02.gif

コード全体はこんな感じ

Mainview.ux
<App>
    <ClientPanel>
        <JavaScript>
            var _hikes = [
                {
                    id: 0,
                    name: "Tricky Trails",
                    location: "Lakebed, Utah",
                    distance: 10.4,
                    rating: 4,
                    comments: "This hike was nice and hike-like. Glad I didn't bring a bike."
                },
                {
                    id: 1,
                    name: "Mondo Mountains",
                    location: "Black Hills, South Dakota",
                    distance: 20.86,
                    rating: 3,
                    comments: "Not the best, but would probably do again. Note to self: don't forget the sandwiches next time."
                },
                {
                    id: 2,
                    name: "Pesky Peaks",
                    location: "Bergenhagen, Norway",
                    distance: 8.2,
                    rating: 5,
                    comments: "Short but SO sweet!!"
                },
                {
                    id: 3,
                    name: "Rad Rivers",
                    location: "Moriyama, Japan",
                    distance: 12.3,
                    rating: 4,
                    comments: "Took my time with this one. Great view!"
                },
                {
                    id: 4,
                    name: "Dangerous Dirt",
                    location: "Cactus, Arizona",
                    distance: 19.34,
                    rating: 2,
                    comments: "Too long, too hot. Also that snakebite wasn't very fun."
                }
            ];

            var Observable = require("FuseJS/Observable")

            var hike = Observable();
            var _name = hike.map(function(x) { return x.name; });
            var _location = hike.map(function(x) { return x.location; });
            var _distance = hike.map(function(x) { return x.distance; });
            var _rating = hike.map(function(x) { return x.rating; });
            var _comments = hike.map(function(x) { return x.comments; });

            function chooseHike(_item) {
                hike.value = _item.data;
            }

            module.exports = {
                hikes: _hikes,
                name: _name,
                location: _location,
                distance: _distance,
                rating: _rating,
                comments: _comments,
                chooseHike: chooseHike
            };
        </JavaScript>
        <ScrollView>
            <StackPanel>
                <Each Items="{hikes}">
                    <Button Text="{name}" Clicked="{chooseHike}" />
                </Each>
                <Text>Name:</Text>
                <TextBox Value="{name}" />

                <Text>Location:</Text>
                <TextBox Value="{location}" />

                <Text>Distance (km):</Text>
                <TextBox Value="{distance}" InputHint="Decimal" />

                <Text>Rating:</Text>
                <TextBox Value="{rating}" InputHint="Integer" />

                <Text>Comments:</Text>
                <TextView Value="{comments}" TextWrapping="Wrap" />
            </StackPanel>
        </ScrollView>
    </ClientPanel>
</App>

今回登場したFuseの機能たち

明日は

各ビューを完全に違う画面に分離して、コンポーネントっぽくしたいと思います!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0