Q:

I need a clean way to access parent scope in knockout foreach

I have a lot of places where I use knockout data bound foreach loops.  A good example would be a list of items, with a click button on the right side that says "edit".   I find myself writing code that looks like the following:
<div data-bind="foreach: myListData">
    ... other divs ...
    <button data-bind="click: $parent.editItem.bind($data)">View</button>
</div>

The editItem function would then look something like the following:
editItem: function (review, data) {
    window.location = "/item/edit/" + review.Id();
},

I find using $parent to be an antipattern, and I also think that using .bind and the knockout-only $data all on the same line is rather cryptic, especially if a developer is not intimately familiar with knockout.   
Is there a better, cleaner way to write parent scope accessed functions in a knockout foreach?

A:

You can put the editItem function on each Review or pass in a reference to the view model that has the editItem function defined on it.
I haven't tested the following sample but it should give you an idea.
function Review(review, vm) {
    var self = this;
    review = review || {};
    self.vm = vm;
    self.Id = ko.observable(review.Id || 0);

    // More properties if needed
}

// Add an editItem prototype to each Review
Review.prototype.editItem = function(review) {
    // The bound item is passed in with the click binding
    window.location = "/item/edit/" + review.Id();

    // Or without using the item passed
    // window.location = "/item/edit/" + this.Id();

    // Or using the editItem function on the view model
    // this.editItem = this.vm.editItem(review);
};

function ReviewViewModel() {
    var self = this;
    self.myListData = ko.observableArray([]);

    // Add some sample data to the observable array
    var myListData = [];
    myListData.push(new Review({ Id: 1}, self));
    myListData.push(new Review({ Id: 2}, self));
    myListData.push(new Review({ Id: 3}, self));
    myListData.push(new Review({ Id: 4}, self));

    self.myListData(myListData);

    // If you would rather have the editItem function on the view model
    self.editItem = function(review) {
        window.location = "/item/edit/" + review.Id();
    };
}

// Markup
<button data-bind="click: editItem">View</button>

