20

This puzzles me. It must be something small I'm not seeing. I'm trying to load a very simple observableArray in knockout with an ajax call.

javascript

// we bind the array to the view model property with an empty array.
var data = [];   
var viewModel = {
    vendors: ko.observableArray(data)
};
ko.applyBindings(viewModel);

$(function () {
    // on this click event, we popular the observable array
    $('#load').click(function () {
        // WORKS. Html is updated appropriately.
        viewModel.vendors([{ "Id": "01" },{ "Id": "02" },{ "Id": "03" }]);

        // DOES NOT WORK. Fiddler2 shows the same exact json string come back 
        // as in the example above, and the success function is being called.
        $.ajax({
            url: '/vendors/10',
            dataType: 'json',
            success: function (data) {
                viewModel.vendors(data);
            }
        });
    });
});

html

<button id="load">Load</button>
<ul data-bind="template: { foreach: vendors }">
    <li><span data-bind="text: Id"></span></li>
</ul>

Question: Why does the successful ajax call, who's data variable value matches byte-for-byte the hard typed value, not trigger the html refresh?

CaptainBli
  • 4,121
  • 4
  • 39
  • 58
one.beat.consumer
  • 9,414
  • 11
  • 55
  • 98

5 Answers5

11

There is no reason this would not work fine. As this demonstrates.

http://jsfiddle.net/madcapnmckay/EYueU/

I would check that the ajax post is actually returning json data and that that json is an array and that it's being parsed correctly.

I had to tweak the ajax call to get the fiddle ajax handlers to work correctly.

Nothing more I can think of.

Hope this helps.

madcapnmckay
  • 15,782
  • 6
  • 61
  • 78
  • thanks for validating my sanity... i'll look closer again. maybe MVC suck in a little wrapper or something... – one.beat.consumer Mar 16 '12 at 05:51
  • Yeh. Firebug the request response, verify you are getting json and then verify jquery is parsing it to an object. – madcapnmckay Mar 16 '12 at 05:55
  • it is json for certain... the C# code looks like `return Json(list, JsonResponseBehavior.AllowGet);` where `list` is an ICollection` so I know it is JSON. Add to that, that Fiddler2 shows the data in its JSON view correctly... it's in the javascript somewhere. i'll post again tomorrow with more info when im at work – one.beat.consumer Mar 16 '12 at 05:58
0
var self=this;
//var self first line in model

$.ajax({
            url: ",
            dataType: "json",
            contentType: 'application/json',
            type: "POST",
            data: JSON.stringify({ }),
            processdata: true,

            beforeSend: function () {
                $.mobile.loading('show');
            },

            error: function (xhr, textStatus, errorThrown) {
                alert('Sorry!');
            },

            success: function (data) {

                $.mobile.loading('hide');
                if (data.result!= '') {
                    self.vendors(data.result);



                } else {
                    self.vendors({something});

                }
            }
        });

Use self.vendors not this viewModel.vendors

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
Stipe
  • 36
  • 3
0

Here is what I done in my MVC .net app with knockout and jquery.

// Scripts/groItems.js
(function () {

    var ViewModel = function () {
        items = ko.observableArray(),
            ItemName = ko.observable(),
            Img = ko.observable(),
            Qty = ko.observable()
    }

    $.getJSON('/Items2/AllItems', function (data) {
        for (var i = 0; i < data.length; i++) {
            self.items.push(data[i]);
        }
    });

    var vm = new ViewModel();

    $(function () {
        ko.applyBindings(vm);
    });

}());
@model IEnumerable<GroModel.Item>
@{
    ViewBag.Title = "Index";
}

<p>
    @Html.ActionLink("Create New", "Create")
</p>

<div data-bind="text: items().length"></div>
<table class="container table table-hover">
    <thead>
        <tr>
            <th>Item name</th>
            <th>img</th>
            <th>qty</th>
        </tr>
    </thead>
    <tbody data-bind="foreach: items">
        <tr>
            <td data-bind="text: ItemName"></td>
            <td data-bind="text: Img"></td>
            <td data-bind="text: Qty"></td>
        </tr>
    </tbody>
</table>

@section Scripts {
    <script src="~/Scripts/knockout-3.4.2.js"></script>
    <script src="~/Scripts/groItems.js"></script>
}

Following is part of my code at the Items2Controller.cs

    private GroContext db = new GroContext();
    public JsonResult AllItems()
    {
        return Json(db.Items.ToList(), JsonRequestBehavior.AllowGet);
    }

enter image description here

Hope this will help. Thanks

Community
  • 1
  • 1
user2662006
  • 2,246
  • 22
  • 16
-2

We can use a simple JavaScript util function as a work-around.

Instead of viewModel.vendors(data);, wrapping with eval (research the dangers of eval first) will work.

eval("viewModel.vendors("+JSON.stringify(data)+");");
JabberwockyDecompiler
  • 3,318
  • 2
  • 42
  • 54
Venkat
  • 3
  • 1
-3

This is bug I think, Knockout's sample is working when we use it with wrapper class:

public class ResultWrapper
{
    public Title {get;set;}
    public List<Result> {get;set;}
}

http://learn.knockoutjs.com/#/?tutorial=webmail

But if we return Results directly there is no way to bind it. (without extra applyBindings!)

Oguz Karadenizli
  • 3,449
  • 6
  • 38
  • 73