2

Fiddle

I'm trying to use knockout.js with the ES5 plugin, but I'm not able to get deleting from an array to work.

It seems to work somewhat, you can delete, but there is always one item left in the array, but not really somehow. I'm totally confused why this doesn't work like you'd think it would.

What am I doing wrong?

(I have a more complex scenario that is using a durandal widget, but I was able to boil it down to just this, so I think the es5 plugin is the culprit)

Here is my markup:

<div data-bind="foreach: staffList" style="border:1px solid black;">
    <div style="border: 1px solid red;">
        <p data-bind="text: Name"></p>
        <p>
            <button data-bind="click: deleteClickHandler">Delete</button>
        </p>
    </div>
</div>

and script:

function ctor(){
  var self=this;
  self.staffList = [{Name:'one'},{Name:'two'},{Name:'three'},{Name:'four'}];
  ko.track(self.staffList, { deep: true });
  self.deleteClickHandler = function (obj) {
    //TODO show confirm dialog first
    var index = self.staffList.indexOf(obj);
    if (index >= 0) {
      self.staffList.splice(index, 1);
    }
  };
}
ko.applyBindings(ctor);

only other difference in the real world is that I'm getting the data from an API call, but the behavior is the same.

Nateous
  • 757
  • 9
  • 23

2 Answers2

0

The button that is nested within the foreach loop neads to reference the parent, so that would be

<button data-bind="click: $root.deleteClickHandler">Delete</button>

instead of

<button data-bind="click: deleteClickHandler">Delete</button>

I just tested this, and found no remaining items listed on the view. That should solve the issue you are seeing, as I am seeing an empty array after the last item is deleted.

Also, I had to change the ko.applyBindings call to ko.applyBindings(new ctor()); and removed the ko.track call in favor of a normal observable array for the staffList object. Unless there was a specific reason you cannot use the observableArray?

JSFiddle Example

  • Thanks @Jeroen. I was not aware of that, as I am "newer" to utilizing Knockout (within the last 1.5 years). – Incorporeal Logic Apr 20 '16 at 19:48
  • if I can't get es5 working with the durandal widgets I will have to revert back to using plain old KO, not so bad, but the es5 is just awesome, and it makes me sad to think I might have to get rid of it. – Nateous Apr 20 '16 at 20:05
0

Interesting question. I'm not sure yet as to the root cause, but I did manage to find a way to make it work. Some changes I needed:

  • Make ctor a real Constructor function / use it as such;
  • Because of the previous point, you'll need to reference deleteClickHandler with specific scope;
  • Track self, not just the one member;

Here's a sample that works for me:

<div data-bind="foreach: staffList" style="border:1px solid black;">
    <div style="border: 1px solid red;">
        <span data-bind="text: Name"></span>
        <button data-bind="click: $root.deleteClickHandler">Delete</button>
    </div>
</div>
<hr>
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
function ViewModel(){
  var self = this;
  self.staffList = [{Name:'one'},{Name:'two'},{Name:'three'},{Name:'four'}];
  ko.track(self);
  self.deleteClickHandler = function (obj) {
    var index = self.staffList.indexOf(obj);
    if (index >= 0) {
      self.staffList.splice(index, 1);
    }
  };
}
ko.applyBindings(new ViewModel());

In addition, I want ot mention that this is also possible:

  self.deleteClickHandler = function (obj) {
    self.staffList.remove(obj);
  };

Again, I'm not sure why ko.track(self.staffList) didn't work, but the above at least gets you going.

Jeroen
  • 60,696
  • 40
  • 206
  • 339
  • I understand the whole "real constructor" thing. Since I'm using durandal I believe that it news up the ctor, but I will have to make sure that isn't the issue. – Nateous Apr 20 '16 at 19:55
  • as far as `remove` is concerned; I had that at first but it wasn't liking that, I thought that was a knockout addition, but not es5? I'll have to revisit that too. – Nateous Apr 20 '16 at 19:56
  • the only difference I am seeing is that tracking `self` instead of `staffList` changes something. Let me try this on my code and see if that is the issue. – Nateous Apr 20 '16 at 20:00
  • 1
    well this definitely solves my boiled down issue, but I'm still having issues with this inside of a durandal widget. i'll have to ask a different question for that if I can boil it down to something simpler. – Nateous Apr 20 '16 at 20:04