Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Knockoutjs binding objects issue

I'm studying knockoutjs and having some issues. I have ASP.NET MVC page with a method returning list of three Car objects is JSON. I than map it to select in HTML view and I want to display cost of a selected car on selection change. The problem is that a name of a car is visible while a price is not ('A Mercedes-Benz costs .'). What it could be? Thanks in advance! Controller:

public class Car
{
    public string Make { get; set; }
    public decimal Price { get; set; }
}
public JsonResult GetCars()
{
    List<Car> cars = new List<Car>();
    cars.Add(new Car { Make = "Mercedes-Benz", Price = 103000 });
    cars.Add(new Car { Make = "Toyota", Price = 37000 });
    cars.Add(new Car { Make = "Huyndai", Price = 17000 });
    return Json(cars, JsonRequestBehavior.AllowGet);
}

And View with Javascript code:

<head>
    <script type="text/javascript" src="~/Scripts/jquery-2.0.3.min.js"></script>
    <script type="text/javascript" src="~/Scripts/knockout-3.0.0.js"></script>
    <script type="text/javascript">
        $(document).ready(function () {
            function Car(data) {
                this.Make = ko.observable(data.Make);
                this.Price = ko.observable(data.Price);
            }

            function CarsViewModel() {
                var self = this;
                //Data
                self.someOptions = ko.observableArray([]);
                self.myOption = ko.observable();

                //Operations
                self.initData = function () {
                    $.get('/Home/GetCars', function (data) {
                        var mappedCars = $.map(data, function (item) { return new Car(item) });
                        self.someOptions(mappedCars);
                    });
                }
            }

            ko.applyBindings(new CarsViewModel());
        });

    </script>
</head>
<body>
    <div>
        <button data-bind="click: initData">Load data</button>
        <h4>Preview</h4>
        <p>
            <select data-bind="options: someOptions, optionsText: 'Make', value: myOption"></select><br />
            A <span data-bind="text: myOption().Make"></span> costs <span data-bind="text: myOption().Price"></span>.
        </p>
    </div>
</body>
like image 593
IDeveloper Avatar asked Oct 31 '13 06:10

IDeveloper


1 Answers

If you check your browser's JavaScript console you should see the following error:

Uncaught TypeError: Unable to process binding "text: function (){return myOption().Make }" Message: Cannot read property 'Make' of undefined

You get this error because when your page is loaded your myOption is empty so it does not have a Make and Price properties. So KO cannot execute the binding data-bind="text: myOption().Make" and it stops with the processing of the further bindings.

After calling initData now you have something in myOption but still all the bindings after the data-bind="text: myOption().Make" won't work anymore.

To solve this there are multiple ways like:

  • using a default value in myOption
  • check for null in your bindings with data-bind="text: myOption() && myOption().Make"
  • or use the with binding

Here is an example for the with binding:

<!-- ko with: myOption -->
   A <span data-bind="text: Make"></span> 
   costs <span data-bind="text: Price"></span>.
<!-- /ko -->

Demo JSFiddle.

like image 178
nemesv Avatar answered Sep 26 '22 17:09

nemesv