0

I'm currently using Knockout to render my HTML page, but I'm stuck when I'm trying to render my HTML when the data is stored in a simple JSON file.

The Json file is here:

{
    "name": "Office Web Controls 2014"
}

Here's the function to load my Json string:

<script type="text/javascript">
        function AppViewModel() {
            this.data = { };

            $.getJSON("Resources/Data/Ribbon.json", function(retrievedData) {
                this.data = ko.mapping.fromJSON(retrievedData);
                console.log(this.data);
            });
        }

    // Activates knockout.js
    ko.applyBindings(new AppViewModel());
</script>

And I would like to bind it to the following HTML:

<div data-bind="text: data.name">
</div>

I've tried very different things but none are working, so if anybody has an idea on how to accomplish this.

Complexity
  • 5,682
  • 6
  • 41
  • 84
  • Now SO supports working JS snippets. Something like your issue would be easier to solve with a working sample.. – Matías Fidemraizer Sep 24 '14 at 21:17
  • But I will not be able to load up a file through an ajax request... – Complexity Sep 24 '14 at 21:19
  • I would guess the issue is with the scope of `this`. I would define `var _this = this;` in `AppViewModel` and use `_this.data` in the callback – njzk2 Sep 24 '14 at 21:19
  • You should simplify it and hardcode the json as a string :D – Matías Fidemraizer Sep 24 '14 at 21:19
  • That doesn't do the trick @njzk2. Dimplifying it would not work as it seems that the issue is in my getJSon, the console.log does show me the correct values, but if I move the log out of the getJSON function, the data is empty. – Complexity Sep 24 '14 at 21:20
  • actually, after looking a little more into knockout, there may also be some sync issue – njzk2 Sep 24 '14 at 21:21
  • And I think that it's a sync issue @njzk2 but do you have any idea on how to solve this one. I'm new to knockout. – Complexity Sep 24 '14 at 21:22
  • possibly call the ajax, then call applyBindings with something like `ko.applyBindings({data: data})` from the call back – njzk2 Sep 24 '14 at 21:43

2 Answers2

1

Finally, after a long search, I've managed to find the solution. For anyone who's intrested, here it is:

<div data-bind="template: {name: 'OfficeWebControls-Title', data: ribbonViewModel}">

</div>

And finally the script:

<script type="text/javascript">
    var ribbonViewModel;

      $.getJSON("Resources/Data/Ribbon.json", function(data) { 
        ribbonViewModel = ko.mapping.fromJS(data);
        ko.applyBindings(ribbonViewModel);
      });
</script>
Complexity
  • 5,682
  • 6
  • 41
  • 84
0

The reason it wasn't working is two fold:

  1. The this pointer in the call back function is not pointing to your vm
  2. The data property of your vm needs to be converted to an observable
    • The $.getJSON call will execute asynchronously and the response will be handled after the ko.applyBindings call. This means that you'll be changing the value of the data property after it's bound to the UI. For the UI to receive changes after it is bound the properties on the view model will need to be wrapped in observables.

Example

function AppViewModel() {
     //remember the this pointer for the call back handler
     var self = this;
     //set default data to an observable
     self.data = ko.observable(null);

     $.getJSON("Resources/Data/Ribbon.json", function(retrievedData) {
            //use self to reference properties on the vm in a call back handler
            self.data(retrievedData);
            console.log(self.data());
        });
}

ko.applyBindings(new AppViewModel());

For this to work the view will also need to change.

<!-- ko if:data -->
<div data-bind="text: data().name"></div>
<!-- /ko -->

fiddle

Community
  • 1
  • 1
Aaron Carlson
  • 5,522
  • 4
  • 31
  • 35