2

I created a ASP.Net MVC 5 project and used Knockout.js library.

I have a View called Statement which basically shows the a table with a couple of Transaction items.

My complete Statement.cshtml is as follow:

@using Newtonsoft.Json;
@model IEnumerable<ATMMVCLearning.Models.Transaction>

@{
    ViewBag.Title = "Statement";
}

<h2>Statement</h2>

<table class="table table-striped table-bordered">
  <thead>
    <tr>
      <td><strong>Transaction ID</strong></td>
      <td><strong>Amount</strong></td>
    </tr>
  </thead>
  <tbody data-bind="foreach:currentTransactions">
    <tr>
      <td data-bind="text:Id"></td>
      <td data-bind="text:formattedPrice"></td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <td colspan="2">
        <span data-bind="click:previousPage" class="glyphicon glyphicon-circle-arrow-left"
              style="cursor:pointer;"></span>
        <span data-bind="text:currentPage"></span>
        <span data-bind="click:nextPage"class="glyphicon glyphicon-circle-arrow-right"
              style="cursor:pointer;"></span>
      </td>
    </tr>
  </tfoot>
</table>

<script src="~/Scripts/knockout-3.4.0.js"></script>
<script>
  function formattedPrice(amount) {
    var price = amount.toFixed(2);
    return price;
  }

  function StatementViewModel() {
    var self = this;

    //properties
    //note that there is a ko.observableArray for making bindings for array
    self.transactions = @Html.Raw(JsonConvert.SerializeObject(Model, new JsonSerializerSettings {
                      ReferenceLoopHandling = ReferenceLoopHandling.Ignore}));
    //TODO: embed  transactions from server as JSON array    
    self.pageSize = 5; //number of transactions to display per page
    self.currentPage = ko.observable(1); //the first observable. If the page changes, then the grid changes
    self.currentTransactions = ko.computed(function () {
      var startIndex = (self.currentPage() - 1) * self.pageSize; //because currentPage is an observable, we get the value by calling it like a function
      var endIndex = startIndex + self.pageSize;
      return self.transactions.slice(startIndex, endIndex);
    });

    //methods to move the page forward and backward
    self.nextPage = function () {
      self.currentPage(self.currentPage() + 1);
    };

    self.previousPage = function () {
      self.currentPage(self.currentPage() - 1);
    };
  };

  ko.applyBindings(new StatementViewModel()); //note this apply bindings, used extensively in KnockOut
</script>

As you can see in the <tbody> I have two <td> elements which have data-bind attribute:

  <tbody data-bind="foreach:currentTransactions">
    <tr>
      <td data-bind="text:Id"></td>
      <td data-bind="text:formattedPrice"></td>
    </tr>
  </tbody>

And the formattedPrice can be referred to the script section below:

  function formattedPrice(amount) {
    var price = amount.toFixed(2);
    return price;
  }

Now, I expect the resulting View when it is rendered should show a table with 5 transactions each page, where each table row shows an Id as well as its transaction amount. I.e. something like:

1  100.00
2  150.00
3  -40.00
4  111.11
5  787.33

However, when I render the page, I got the following result:

enter image description here

Instead of Id and amount, I got Id and javascript.

Any idea?

Update:

The Transaction class is as follow:

public class Transaction {
    public int Id { get; set; } //this is internally used, not need to have anything

    [Required]
    [DataType(DataType.Currency)]
    public decimal Amount { get; set; }

    [Required]
    public int CheckingAccountId{ get; set; }

    public virtual CheckingAccount CheckingAccount { get; set; } //this is to force the entity framework to recognize this as a foreign key
}

2 Answers 2

3

Since formattedPrice is not part of your view-model, Knockout won't automatically unwrap it, nor will it pass it the amount argument.

Try this instead:

<td data-bind="text: formattedPrice(Amount)"></td>
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for the answer, I appreciate that. How do we make the formattedPrice into View-Model? I tried the solution you gave <td data-bind="text: formattedPrice(amount)"></td> unfortunately, it doesn't work..
What is the structure of your Transaction model?
Updated my question with the structure of my Transaction model
That's it! You nail it! :D thanks! So it depends on the Transaction model and not the JavaScript...
@Ian, When Knockout parses the expression, it recognizes that Amount is part of the current scope (which is the current object being iterated-on in the foreach: currentTransactions), and passes its value to the global window.formattedPrice function.
|
0

Price probably needs to be computed field and you need to bind to price (I think). It's been a while since I did Knockoutjs.

2 Comments

Thanks for the answer... what does it mean by "computed field"? How do we bind the price?
you are right, it needs to be correctly bound. haim770 has answered it, but what you mention here is not far from the answer too (except that you do not have code)... Thanks, upvoted.

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.