Backbone JS with Knockback JS and Knocokout JS

by imehesz

HTML

<script src="http://underscorejs.org/underscore.js"></script>
<script src="http://backbonejs.org/backbone.js"></script>
<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.1.0.debug.js"></script>
<script src="https://raw.github.com/kmalakoff/knockback/0.15.4/knockback.js"></script>
For Sale
<div id='auction'>
  <h2 data-bind='text: title'></h2>
  <img id="modelImage">
  <div><label>Time left: </label><span data-bind='text: timeRemaining'></span></div>

  <div class='alert-box' data-bind='visible: endingSoon'>
    <p>Hurry up! Win this item NOW!</p>
  </div>

    <div><label>Highest Bid: </label> $<span data-bind='text: bid'></span> <button id="addbid" data-bind="{click: addBid, hidden: ended}">Bid +$50!</button></div>
    <div><label>Current Bidder: </label> <span data-bind='text: bidder'></span></div>     

</div>

<div class="poweredby">
    powered by <a href="http://backbonejs.org/" target="_blank">BackboneJS</a> and <a href="http://kmalakoff.github.com/knockback" target="_blank">KnockBack JS</a>
</div>

CSS

.alert-box{
    color: #f00;
    border: 1px solid #f00;
    text-align:center;
    font-weight: bolder;
    margin: 5px 0px;
}

#auction{
    border: 1px solid #aaa;
    padding: 10px;
    width: 250px;   
}

label{
    font-weight: bolder;
}

img{
    width: 100px;
}

.poweredby{
    margin-top: 5px;
    font-size: 11px;
    color: #aaa;
}

.poweredby a{
    color: #777;
}

JavaScript

$(document).ready(function() {
    var auction_model,
        auction_view_model;
    
    auction_model = new Backbone.Model({
        title: '20 Sided Die',
        image_url: "http://ecx.images-amazon.com/images/I/41YbHQ0gP6L._SL500_AA300_.jpg",
        timeRemaining: 25,
        endingSoon: false,
        ended: false,
        bid: 200,
        bidder: "Sally"
    });
    
    $('#modelImage').attr('src', auction_model.get('image_url' ));
    
    //auction_view_model = kb.viewModel(auction_model);
    auction_view_model = {
        model: auction_model,
        
        // there is probably a better solution for this ...
        title: kb.observable( auction_model, {key:'title'} ),
        timeRemaining: kb.observable( auction_model, {key:'timeRemaining'} ),
        bid: kb.observable( auction_model, {key:'bid'} ),
        bidder: kb.observable( auction_model, {key:'bidder'} ),
        endingSoon: kb.observable( auction_model,{key: 'endingSoon'} ),
        ended: kb.observable( auction_model,{key: 'ended'} ),
        
        addBid: function(){ 
            this.model.set({
                bid:this.model.get('bid') + 50,
                bidder: 'You'
            });
        }       
    };

    runTimer = function(){
        var item = auction_model;
        if( item.get('timeRemaining') > 0 )
        {
            _.delay(_.bind(updateTimer, this), 1000);
        }
    };
    
    updateTimer = function(){
        var item = auction_model,
            timeleft = item.get( 'timeRemaining' )-1;
    
        item.set({timeRemaining: timeleft});
        
        if( timeleft < 15 )
        {
            item.set({endingSoon: true});
        }        

        if( timeleft > 0 )
        {
            this.runTimer();
        }
        else
        {
            item.set({timeRemaining:"-", endingSoon: false, ended: true});
        }
    };

    // custom handler to hide the button when it's no longer needed
    // there might be a better way, I couldn't find it...