Remove item from list using Knockout.js

I am trying to remove an item from a list. I am using knockout.js with a display plugin. My code is as follows:

Serialize Json

@{ var jsonData = new HtmlString(new JavaScriptSerializer().Serialize(Model));} 

Template

 <script type="text/html" id="imgsList"> {{each model.Imgs}} <div style="float:left; margin: 10px 10px 10px 0;"> <div><a href="${Filename}"><img src="${Filename}" style="width:100px;"></img></a></div> <div data-bind="click: deleteImage">Delete</div> </div> {{/each}} </script> 

Ko javascript

 <script type="text/javascript"> $(function() { //KO Setup var viewModel = { "model": ko.mapping.fromJS(@jsonData), "deleteImage" : function(item) {alert(item.Filename + ' deleted.');} } ko.applyBindings(viewModel); }); </script> 

HTML

 <div data-bind="template: 'imgsList'"></div> 

Question

Everything works as expected. A list of images appears with delete buttons, however, when you click the item.Filename undefined button. Thoughts?

Edit: taken from the KNockout.js manual: โ€œWhen you call your handler, Knockout will supply the current value of the model as the first parameter. This is especially useful if you create some user interface for each element in the collection, and you need to find out which elements of the user interface were pressed. "

It seems like I am not returning the Img object that I expect. I don't know that I'm coming back!

+4
source share
2 answers

When you use the {{each}} syntax in jQuery templates, the data context is related to what the generic template is associated with. In your case, this is a complete view model.

Several variants:

1- you can use your current code and pass the element that you are "attached" to a function of the type ( http://jsfiddle.net/rniemeyer/qB9tp/1/ ):

 <div data-bind="click: function() { $root.deleteImage($value); }">Delete</div> 

Using an abnormal function in data binding is pretty ugly. There are better options.

2- you can use the foreach template binding parameter, which works with jQuery templates and is more efficient than {{each}} like ( http://jsfiddle.net/rniemeyer/qB9tp/2/ ):

 <script type="text/html" id="imgsList"> <div style="float:left; margin: 10px 10px 10px 0;"> <div> <a href="${Filename}">${Filename}</a> </div> <div data-bind="click: $root.deleteImage">Delete</div> </div> </script> <div data-bind="template: { name: 'imgsList', foreach: model.Imgs }"></div> 

Now the template context is a separate image object, and a call to $root.deleteImage will pass it as the first argument.

3- Since the jQuery Templates plugin is deprecated and Knockout now supports native templates, you might want to remove your dependency on the jQuery Templates plugin. You can still use a named template (you just need to replace any jQuery Templates syntax with data binding attributes), for example: http://jsfiddle.net/rniemeyer/qB9tp/3/ or even remove the template and just go with the foreach control flow binding, for example : http://jsfiddle.net/rniemeyer/qB9tp/4/

 <div data-bind="foreach: model.Imgs"> <div style="float:left; margin: 10px 10px 10px 0;"> <div> <a data-bind="text: Filename, attr: { href: Filename }"></a> </div> <div data-bind="click: $root.deleteImage">Delete</div> </div> </div> 

4- Although I prefer option No. 3, you can even use event delegation and attach a live handler, for example: http://jsfiddle.net/rniemeyer/qB9tp/5/

 $("#main").on("click", ".del", function() { var data = ko.dataFor(this); viewModel.deleteImage(data); }); 

This can be especially useful if you bind a large number of the same handlers using click bindings (for example, in a grid).

+6
source

I notice that there is an example of how to do this:

http://blog.stevensanderson.com/2011/12/21/knockout-2-0-0-released/

Check 4. Clearing events where Steve shows an example of an item being removed from the list.

 <h3>Products</h3> <ul data-bind="foreach: products"> <li> <strong data-bind="text: name"></strong> <button data-bind="click: $parent.removeProduct">Delete</button> </li> </ul> 

JavaScript:

  function appViewModel() { var self = this; self.products = ko.observableArray([ { name: "XBox" }, { name: "PlayStation" }, { name: "Banana" }, { name: "Wii" } ]); self.removeProduct = function(product) { self.products.remove(product); } }; ko.applyBindings(new appViewModel()); 

But keep in mind that the above example is for KnockoutJS 2.0, which is the latest version.

+7
source

Source: https://habr.com/ru/post/1388975/


All Articles