0
votes

I would like to add a 'delete comment' button as a form that triggers an ajax request next to each comment that is generated using knockout's foreach binding. comments is an observable array, each comment is an object with username, text, timestamp and commentID members. Loading the following without the <form> element works fine:

<ul data-bind="foreach: comments">
    <li>
        <span data-bind="text: username"></span>
        <ul>
            <li data-bind="text: text"></li>
            <li data-bind="text: timestamp"></li>
            <form data-bind="if: sameUser" method="post" action="deleteComment.php">
                <input data-bind="attr: {id: commentID}, click: deleteComment" type="submit" value="Delete comment">
            </form>
        </ul>
    </li>
</ul>

However, including a <form> element breaks the foreach loop, only one comment is loaded.

I want to use the if: sameUser data-bind so that the delete button is only visible to the user that posted the comment, and the attr: {id: commentID} data-bind to send the right comment ID to delete to the server when the button is clicked, but right now my main concern is loading the form/button in the first place.

What is the correct way to go about this?

1
does sameUser exist on the objects inside the comments array? If not you might need to use if: $parent.sameUser()IrkenInvader
also recommend checking your console to see if bindings are broken, it usually spits out an error with the offending bindingIrkenInvader

1 Answers

2
votes

Not sure if you are writing delete function on comment level or its list level but if are binding the function use $parent to get out of foreach context.

Following is the working example

function viewModel() {
  var self = this;
  
  self.comments = ko.observableArray([]);
  self.isDataLoaded = ko.observable(false);
  
  self.loadData = function(){
    setTimeout(function(){ 
      self.comments.push({username:"A", sameUser:true, commentID:1, text:"This is comment from A"});
      self.comments.push({username:"B", sameUser:true, commentID:2, text:"This is comment from B"});
      self.comments.push({username:"C", sameUser:false, commentID:3, text:"This is comment from C"});
      self.comments.push({username:"D", sameUser:true, commentID:4, text:"This is comment from D"});
      self.isDataLoaded(true);
    }, 2000);
  }
  self.deleteComment = function(data){
    self.comments.remove(data);
  }
}

var vm = new viewModel();
vm.loadData();
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul data-bind="foreach: comments">
    <li>
        <span data-bind="text: username"></span>
        <ul>
            <li data-bind="text: text"></li>
            <!--<li data-bind="text: timestamp"></li> -->
            <form data-bind="if: sameUser" method="post">
                <input data-bind="attr: {id: commentID}, click: $parent.deleteComment" type="submit"        value="Delete comment">
            </form>
        </ul>
    </li>
</ul>