Ramppy Dumppy
Ramppy Dumppy

Reputation: 2817

How to implement paging in "with" bindings in knockout

I have a requirements in my project where I need to put my selected item in the Modal and user can click next to show the next item.

I am using a with binding to display the content of selected in a form. I don't have an idea on how can I apply paging inside a "With" binding.

<div class="container" data-bind="with: itemForEditing">
 <div id="riskRegisterForm" class="modal hide fade">
    <div class="modal-header" style="background:#4bafef; height: 30px;">            
        <h5 style="color:#FFFFFF; font:16px Arial;">Item</h5>
    </div>
    <div class="modal-body" style="background:#fff">
        <div>
            <form class="form-horizontal">
              <div class="control-group">
                <label class="control-label" for="itemName">Name</label>
                <div class="controls">
                    <input type="text" id="itemName" data-bind="value: name" />
                </div>
              </div>
              <div class="control-group">
                <label class="control-label" for="itemPrice">Price</label>
                <div class="controls">
                    <input type="number" step=".01" id="itemPrice" data-bind="value: price" />
                </div>
              </div>                    
            </form>
        </div>
    </div>
    <div class="modal-footer">
        <button type="button" data-dismiss="modal" class="btn" data-bind="click:$parent.revertItem">Cancel</button>
        <button type="button" data-dismiss="modal" class="btn" data-bind="click:$parent.acceptItem">Update</button>            
    </div>
    <span><a href=#>next</a></span>
    <span><a href=#>prev</a></span>
 </div>
 </div>

when I click the next it should autmatically select the next records and put in the contorls. Here is the JsFiddle http://jsfiddle.net/ramon26cruz/Tt96J/6/

Upvotes: 1

Views: 332

Answers (2)

Richard Banks
Richard Banks

Reputation: 2983

I've had a go at this. I changed my tack from above. Basically I created 2 method, a next and a prev. In the methods I find the index of the selected / editable object in the array and the either increment or decrement based on which method has been used. I then update the selected and editable property objects:

var Item = function(data) {
    this.name = ko.observable();
    this.price = ko.observable();
    
    //populate our model with the initial data
    this.update(data);
};

//can pass fresh data to this function at anytime to apply updates or revert to a prior version
Item.prototype.update = function(data) { 
    this.name(data.name || "new item");
    this.price(data.price || 0);
};

var ViewModel = function(items) {
    this.index = 0;
    
    //turn the raw items into Item objects
    this.items = ko.observableArray(ko.utils.arrayMap(items, function(data) {
        return new Item(data);
    }));
    
    //hold the currently selected item
    this.selectedItem = ko.observable();
    
    //make edits to a copy
    this.itemForEditing = ko.observable();
    
    this.selectItem = this.selectItem.bind(this);
    this.acceptItem = this.acceptItem.bind(this);
    this.revertItem = this.revertItem.bind(this);
    this.next = this.next.bind(this);
    this.prev = this.prev.bind(this);
};

ko.utils.extend(ViewModel.prototype, {
    //select an item and make a copy of it for editing
    selectItem: function(item) {
        this.selectedItem(item);
        this.itemForEditing(new Item(ko.toJS(item)));
    },
    
    next:function(){
        var pos = this.items.indexOf(this.selectedItem()) + 1;
        if(pos > this.items().length - 1){pos = 0};
        
        this.selectedItem(this.items()[pos]);
        this.itemForEditing(new Item(ko.toJS(this.items()[pos])));
    },
    
    prev:function(){
        var pos = this.items.indexOf(this.selectedItem()) - 1;
        if(pos < 0){pos = this.items().length - 1};
        
        this.selectedItem(this.items()[pos]);
        this.itemForEditing(new Item(ko.toJS(this.items()[pos])));
    },
    
    acceptItem: function(item) {
        var selected = this.selectedItem(),
            edited = ko.toJS(this.itemForEditing()); //clean copy of edited
        
        //apply updates from the edited item to the selected item
        selected.update(edited);
        
        //clear selected item
        this.selectedItem(null);
        this.itemForEditing(null);
    },
    
    //just throw away the edited item and clear the selected observables
    revertItem: function() {
        this.selectedItem(null);
        this.itemForEditing(null);
    }
});

ko.applyBindings(new ViewModel([
    { name: "Cheese", price: 2.50 },
    { name: "Pepperoni", price: 3.25 },
    { name: "Deluxe", price: 4.25 }
]));

Here's a link to my JS Fiddle.

Upvotes: 2

Tomalak
Tomalak

Reputation: 338336

One way to do it would be like this:

<div class="container" data-bind="with: itemForEditing">
    <!-- ... -->
    <span><a href=# data-bind="click: $root.nextItem">next</a></span>
    <span><a href=# data-bind="click: $root.prevItem">prev</a></span>
</div>

and

ko.utils.extend(ViewModel.prototype, {
    // offset the selected item by a certain amount (i.e. -1/+1 for next/prev)
    offsetItem: function (by) {
        var items = this.items(),
            i = ko.utils.arrayIndexOf(items, this.selectedItem()),
            newItem = (i > -1) ? items[i + by] : null;

        if (newItem) {
            this.selectItem(newItem);
        }
    },
    prevItem: function () {
        this.offsetItem(-1);
    },
    nextItem: function () {
        this.offsetItem(1);
    },
    /* ... */
}

See it live http://jsfiddle.net/Tt96J/11/

Upvotes: 1

Related Questions