5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

KnockoutJs Tutorial|カスタムバインディング

Last updated at Posted at 2014-11-02

KnockoutJs Tutorial|Creating custom bindings

knockout.js tutorial4こめhttp://learn.knockoutjs.com/#/?tutorial=collections

bindingを自作します。日本語で軽くコメントアウト入れました。(まずチュートリアルをみて、よくわからなかったら見てみてください)。

つくりたいバインディング

もともとのソースが多いのでわかりづらいですが、やりたいバインディングは、

  • starRating
  • fadeVisible
  • jqButton

の3つです。

HTML

<h3 data-bind="text: question"></h3>
<p>Please distribute <b data-bind="text: pointsBudget"></b> points between the following options.</p>

<table>
    <thead><tr><th>Option</th><th>Importance</th></tr></thead>
    <tbody data-bind="foreach: answers">
        <tr>
            <td data-bind="text: answerText"></td>

            <!-- ↓starRatingのバインディング。pointsの部分がJS側のvalueAccessorになる -->
            <td data-bind="starRating: points"></td>

            <td><select data-bind="options: [1,2,3,4,5], value: points"></select></td>
        </tr>    
    </tbody>
</table>

<!-- ↓fadeVisibleのバインディング。「pointsUsed() > pointsBudget」のboolean値がJS側のvalueAccessorになる -->
<h3 data-bind="fadeVisible: pointsUsed() > pointsBudget">You've used too many points! Please remove some.</h3>

<p>You've got <b data-bind="text: pointsBudget - pointsUsed()"></b> points left to use.</p>

<!-- ↓jqButtonのバインディング。「{ enable: pointsUsed() <= pointsBudget }」のboolean値がJS側のvalueAccessorに。jQuery UIをつかっているので通常の書き方と異なる。 -->
<button data-bind="jqButton: { enable: pointsUsed() <= pointsBudget }, click: save">Finished</button>

JS

function Answer(text) { this.answerText = text; this.points = ko.observable(1); }

function SurveyViewModel(question, pointsBudget, answers) {

    // ===== starRating =====
    ko.bindingHandlers.starRating = {
        init: function(element, valueAccessor) {
            $(element).addClass("starRating");
            for (var i = 0; i < 5; i++)
               $("<span>").appendTo(element);

            // Handle mouse events on the stars
            $("span", element).each(function(index) {
                $(this).hover(

                    // hoverしたらクラスを追加
                    function() { $(this).prevAll().add(this).addClass("hoverChosen") }, 
                    function() { $(this).prevAll().add(this).removeClass("hoverChosen") }                

                ).click(function() { 

                   // clickしたら、valueAccessorを更新。eachをつかってindexを取得している
                   var observable = valueAccessor();  // Get the associated observable
                   observable(index+1);               // Write the new rating to it

                 }); 
            });
        },
        update: function(element, valueAccessor) {
            // Give the first x stars the "chosen" class, where x <= rating
            var observable = valueAccessor();
            $("span", element).each(function(index) {
                $(this).toggleClass("chosen", index < observable());
            });
        }
    };
    // ===== starRating end =====

    // ===== jqButton =====
    ko.bindingHandlers.jqButton = {
        init: function(element) {
           $(element).button(); // jQuery UIのbuttonに変える
        },
        update: function(element, valueAccessor) {
            var currentValue = valueAccessor();
            // "disabled"プロバティを更新
            $(element).button("option", "disabled", currentValue.enable === false);
        }
    };
    // ===== jqButton end =====

    // ===== fadeVisible =====
    ko.bindingHandlers.fadeVisible = {
        init: function(element, valueAccessor) {
            // visible/invisibleかを初期値によって判別
            var shouldDisplay = valueAccessor();
            $(element).toggle(shouldDisplay);
        },
        update: function(element, valueAccessor) {
            // visible/invisibleかを更新
            var shouldDisplay = valueAccessor();
            shouldDisplay ? $(element).fadeIn() : $(element).fadeOut();
        } 
    };
    // ===== fadeVisible end =====

    this.question = question;
    this.pointsBudget = pointsBudget;
    this.answers = $.map(answers, function(text) { return new Answer(text) });
    this.save = function() { alert('To do') };
                       
    this.pointsUsed = ko.computed(function() {
        var total = 0;
        for (var i = 0; i < this.answers.length; i++)
            total += this.answers[i].points();
        return total;        
    }, this);
}

ko.applyBindings(new SurveyViewModel("Which factors affect your technology choices?", 10, [
   "Functionality, compatibility, pricing - all that boring stuff",
   "How often it is mentioned on Hacker News",    
   "Number of gradients/dropshadows on project homepage",        
   "Totally believable testimonials on project homepage"
]));
5
5
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
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?