1

I'm working with Knockout.js and asp .net mvc. The problem with below code is that "removeItem" event is not triggered. I've been struggling with this for days and tried different alternatives but nothing seems to work. There are no javascript errors on the page, it loads correctly but when I click on the button nothing happens. Any help will be appreciated.

<tbody data-bind="foreach: categories" id="tablebody">
                    <tr>
                        <td class="table-cell-id">
                            <span data-bind="text: $index"></span>
                        </td>
                        <td>
                            <a class="small" data-bind="text: Name, attr: { href: $parent.onViewDetails($data) }"></a>
                        </td>
                        <td>
                            <a class="small text-nowrap" data-bind="text: Code, attr: { href: $parent.onViewDetails($data) }"></a>
                        </td>
                        <td class="text-center" data-bind="text: CreationDateInFormat"></td>
                        <td class="text-center text-nowrap" data-bind="text: CreatedByName"></td>
                        <td class="text-center" data-bind="text: ModificationDateInFormat"></td>
                        <td class="text-center text-nowrap" data-bind="text: ModifiedByName"></td>
                        <td>
                            <span class="label label-default" data-bind="text: StatusName"></span>
                        </td>
                        <td class="table-cell-actions">
                            <div class="btn-group">
                                <button class="item-action" type="button" id="itemOptions1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                    <span class="glyphicon glyphicon-option-vertical" aria-hidden="true"></span>
                                </button>
                                <ul class="dropdown-menu dropdown-menu-right" aria-labelledby="itemOptions1">
                                    <li>
                                        <a class="btn btn-dropdown" data-bind="attr: { href: $parent.onViewDetails($data) }">
                                            <span class="glyphicon glyphicon-eye-open offset-right" aria-hidden="true"></span>
                                            Details
                                        </a>
                                    </li>
                                    <li>
                                        <a class="btn btn-dropdown" data-bind="attr: { href: $parent.onEditItem($data) }">
                                            <span class="glyphicon glyphicon-pencil offset-right" aria-hidden="true"></span>
                                            Edit
                                        </a>
                                    </li>
                                    <li>
                                        <button type="button" class="btn btn-dropdown" data-bind="click: removeItem">
                                            <span class="glyphicon glyphicon-remove-sign offset-right" aria-hidden="true"></span>
                                            Delete
                                        </button>
                                    </li>
                                </ul>
                            </div>
                        </td>
                    </tr>
                </tbody>

JS:

<script>
        function MyViewModel() {
            var self = this;

            var categories = [];
            var arrayOfCategories = @Html.HtmlConvertToJson(Model);

            var Item = function (name, code, categoryId, creationDateInFormat, createdByName, modificationDateInFormat, modifiedByName, status) {
                this.Name = name;
                this.Code = code;
                this.CategoryId = categoryId;
                this.CreationDateInFormat = creationDateInFormat;
                this.CreatedByName = createdByName;
                this.ModificationDateInFormat = modificationDateInFormat;
                this.ModifiedByName = modifiedByName;
                this.StatusName = status;
                this.removeItem = function () {
                    alert(this.Name);
                }
            };

            arrayOfCategories.forEach(function(element) {
                categories.push(
                    new Item(element.Name,
                        element.Code,
                        element.CategoryId,
                        element.CreationDateInFormat,
                        element.CreatedByName,
                        element.ModificationDateInFormat,
                        element.ModifiedByName,
                        element.Status.Name
                    )
                );
            });


            var pageUrls = {};
            pageUrls.editUrl = '@Url.Action("Edit", new { id = 0 })';
            pageUrls.detailsUrl = '@Url.Action("Details", new { id = 0 })';

            self.categories = ko.observableArray(categories);

            self.onEditItem = function(data) {
                return pageUrls.editUrl.replace('0', data.CategoryId);
            };

            self.onViewDetails = function(data) {
                return pageUrls.detailsUrl.replace('0', data.CategoryId);
            };
        }

        var viewModel = new MyViewModel();
        ko.applyBindings(viewModel);
    </script>
2
  • Which button? There is more than one in your code. Also have you tried creating a Minimal, Complete and Verifiable example? See stackoverflow.com/help/mcve Commented Apr 13, 2018 at 14:32
  • Thanks for you answer @MartinBrown. I noticed that nothing was working for that delete button because of my reference to bootstrap-iu.js reference. When I removed it, my code worked prefectly Commented Apr 16, 2018 at 15:24

1 Answer 1

1

I did get errors copying your code to a snippet.

  1. Is your <tbody> element inside a <table>? Table configurations that do not respect the spec often don't get rendered correctly.
  2. Your click handler needs to be correctly bound to a category using either .bind(this) or some var self = this pattern.

Fixing these does get your button to work as intended (the category name is alerted).

function MyViewModel() {
  var self = this;

  var categories = [];
  var arrayOfCategories = [{
    Code: 1,
    Name: "Some name",
    Status: {}
  }]

  var Item = function(name, code, categoryId, creationDateInFormat, createdByName, modificationDateInFormat, modifiedByName, status) {
    this.Name = name;
    this.Code = code;
    this.CategoryId = categoryId;
    this.CreationDateInFormat = creationDateInFormat;
    this.CreatedByName = createdByName;
    this.ModificationDateInFormat = modificationDateInFormat;
    this.ModifiedByName = modifiedByName;
    this.StatusName = status;
    this.removeItem = function() {
      alert(this.Name);
    }.bind(this)
  };

  arrayOfCategories.forEach(function(element) {
    categories.push(
      new Item(element.Name,
        element.Code,
        element.CategoryId,
        element.CreationDateInFormat,
        element.CreatedByName,
        element.ModificationDateInFormat,
        element.ModifiedByName,
        element.Status.Name
      )
    );
  });


  var pageUrls = {};
  pageUrls.editUrl = '@Url.Action("Edit", new { id = 0 })';
  pageUrls.detailsUrl = '@Url.Action("Details", new { id = 0 })';

  self.categories = ko.observableArray(categories);

  self.onEditItem = function(data) {
    return pageUrls.editUrl.replace('0', data.CategoryId);
  };

  self.onViewDetails = function(data) {
    return pageUrls.detailsUrl.replace('0', data.CategoryId);
  };
}

var viewModel = new MyViewModel();
ko.applyBindings(viewModel);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<table>
  <tbody data-bind="foreach: categories" id="tablebody">
    <tr>
      <td class="table-cell-id">
        <span data-bind="text: $index"></span>
      </td>
      <td>
        <a class="small" data-bind="text: Name, attr: { href: $parent.onViewDetails($data) }"></a>
      </td>
      <td>
        <a class="small text-nowrap" data-bind="text: Code, attr: { href: $parent.onViewDetails($data) }"></a>
      </td>
      <td class="text-center" data-bind="text: CreationDateInFormat"></td>
      <td class="text-center text-nowrap" data-bind="text: CreatedByName"></td>
      <td class="text-center" data-bind="text: ModificationDateInFormat"></td>
      <td class="text-center text-nowrap" data-bind="text: ModifiedByName"></td>
      <td>
        <span class="label label-default" data-bind="text: StatusName"></span>
      </td>
      <td class="table-cell-actions">
        <div class="btn-group">
          <button class="item-action" type="button" id="itemOptions1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                    <span class="glyphicon glyphicon-option-vertical" aria-hidden="true"></span>
                                </button>
          <ul class="dropdown-menu dropdown-menu-right" aria-labelledby="itemOptions1">
            <li>
              <a class="btn btn-dropdown" data-bind="attr: { href: $parent.onViewDetails($data) }">
                <span class="glyphicon glyphicon-eye-open offset-right" aria-hidden="true"></span> Details
              </a>
            </li>
            <li>
              <a class="btn btn-dropdown" data-bind="attr: { href: $parent.onEditItem($data) }">
                <span class="glyphicon glyphicon-pencil offset-right" aria-hidden="true"></span> Edit
              </a>
            </li>
            <li>
              <button type="button" class="btn btn-dropdown" data-bind="click: removeItem">
                                            <span class="glyphicon glyphicon-remove-sign offset-right" aria-hidden="true"></span>
                                            Delete
                                        </button>
            </li>
          </ul>
        </div>
      </td>
    </tr>
  </tbody>
</table>

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, it is inside a <table>. Regarding #2 i've tried that too. Anyway, thanks for your reply but I noticed that nothing was working for that delete button because of my reference to bootstrap-iu.js reference. When I removed it, my code workd prefectly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.