How do I reverse order KnockoutJS array items so they are added to the top of the screen in descending order

StackOverflow https://stackoverflow.com/questions/21949892

Pregunta

Need to add new items to an observable array but have them added to the top of the list, not the bottom as in this example. Any ideas please? Have tried .reverse() but obviously there's an issue with the array being dynamically created and displayed...

http://jsfiddle.net/CSFuF/1/ with .reverse() not working

http://jsfiddle.net/CSFuF/ without .reverse()

<!-- End view/edit employees details -->
<ul data-bind="foreach: parents.reverse()">
     <h3 data-bind="visible: $index() == 0">Parents</h3>

    <!-- add / remove parent -->
    <li>          
        <fieldset>
            <h4 data-bind="text: $index()"></h4>
              <p style="float: left">
                <button data-bind='disable: !(children().length > 0), click: toggleChildren'><span data-bind="visible: toggle">-</span><span data-bind="visible: !toggle()">+</span>
                </button>
                <button data-bind='disable: !toggle(), click: addChild'>Add child (+)</button>
            </p>
            <!-- add remove child -->
            <!-- ko if: toggle -->
            <ul class="qtr" data-bind="foreach: children.reverse()">
                 <h4 data-bind="visible: $index() == 0">Children</h4>

                <li>
                    <fieldset>
                        <h4 data-bind="text: $index()"></h4>
                        <button data-bind='click: removeChild'>Remove child (-)</button>
                    </fieldset>
                </li>
            </ul>
            <!-- /ko -->
            <p style="float: right">
                <button data-bind='click: removeParent'>Remove parent (-)</button>
            </p>

        </fieldset>
    </li>
</ul>
<p style="float: right">
    <button data-bind='click: addParent'>Add parent (+)</button>
</p>

JS:

function Parent(children) {
    var self = this;
    //self.name = ko.observable(name);
    self.toggle = ko.observable(true);
    self.children = ko.observableArray(children);
    self.addChild = function () {
        self.children.push(new Child("", self));
    }
    self.removeParent = function (parent) {
        vm.removeParent(self);
    };
    self.removeChild = function (child) {
        self.children.remove(child);
    }
    self.toggleChildren = function () {
        self.toggle(!self.toggle());
    };
}

function Child(name, parent) {
    var self = this;
    self.parent = parent;
    self.removeChild = function () {
        self.parent.removeChild(self);
    };
}

function ParentChildViewModel() {
    var self = this;
    self.parents = ko.observableArray([]);
    self.addParent = function () {
        self.parents.push(new Parent());
    };
    self.removeParent = function (parent) {
        self.parents.remove(parent);
    }
};

var vm = new ParentChildViewModel();
ko.applyBindings(vm);
¿Fue útil?

Solución

Calling reverse() on an observable array reverses the underlying array in place and doesn't return the array. So binding to its return value didn't render anything.

To insert into the beginning of the observable array, use unshift().

You're also using $index to display the index of the array item being rendered. But because you're always traversing from beginning to end, it will always go from 0 to length - 1.

Here's what it looks like with unshift(). I've added a name property and inserted a counter in it so that you can see the order of items in the arrays...

HTML

<!-- End view/edit employees details -->
<ul data-bind="foreach: parents">
     <h3 data-bind="visible: $index == 0">Parents</h3>

    <!-- add / remove parent -->
    <li>          
        <fieldset>
            <h4 data-bind="text: name"></h4>
              <p style="float: left">
                <button data-bind='disable: !(children().length > 0), click: toggleChildren'><span data-bind="visible: toggle">-</span><span data-bind="visible: !toggle()">+</span>
                </button>
                <button data-bind='disable: !toggle(), click: addChild'>Add child (+)</button>
            </p>
            <!-- add remove child -->
            <!-- ko if: toggle -->
            <ul class="qtr" data-bind="foreach: children">
                 <h4 data-bind="visible: $index == 0">Children</h4>

                <li>
                    <fieldset>
                        <h4 data-bind="text: name"></h4>
                        <button data-bind='click: removeChild'>Remove child (-)</button>
                    </fieldset>
                </li>
            </ul>
            <!-- /ko -->
            <p style="float: right">
                <button data-bind='click: removeParent'>Remove parent (-)</button>
            </p>

        </fieldset>
    </li>
</ul>
<p style="float: right">
    <button data-bind='click: addParent'>Add parent (+)</button>
</p>

JavaScript

function Parent(name, children) {
    var self = this;
    self.name = name;
    var childCount = 0;
    //self.name = ko.observable(name);
    self.toggle = ko.observable(true);
    self.children = ko.observableArray(children);
    self.addChild = function () {
        self.children.unshift(new Child(++childCount, self));
    }
    self.removeParent = function (parent) {
        vm.removeParent(self);
    };
    self.removeChild = function (child) {
        self.children.remove(child);
    }
    self.toggleChildren = function () {
        self.toggle(!self.toggle());
    };
}

function Child(name, parent) {
    var self = this;
    self.parent = parent;
    self.name = name;
    self.removeChild = function () {
        self.parent.removeChild(self);
    };
}

function ParentChildViewModel() {
    var self = this;
    var parentCount = 0;
    self.parents = ko.observableArray([]);
    self.addParent = function () {
        self.parents.unshift(new Parent(++parentCount));
    };
    self.removeParent = function (parent) {
        self.parents.remove(parent);
    }
};

var vm = new ParentChildViewModel();
ko.applyBindings(vm);

Fiddle... http://jsfiddle.net/CSFuF/2/

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top