3

I have the following setup on my site. It is working fantastically on any standard browser and any normal mobile browser:

Model:

function SearchTerm(data) {
    this.Term = ko.observable(data.Term);
    this.Stamp = ko.observable(data.Stamp);
}

ViewModel:

function HistoryViewModel() {
    //Data
    var self = this;
    self.searchTerms= ko.observableArray([]);

    // Load history from server
    $.ajax({
        type: "GET",
        url: "/api/history/",
        data: null, 
        success: function (msg) {
            var terms = $.map(msg, function (item) { return new SearchTerm(item) });
            self.searchTerms(terms);
        },
        error: function (xhr, ajaxOptions, thrownError) {
            // Error Handling
        }
    });
}

View:

<div class="title">
            Search History
            <div class="closeBtn"></div>
        </div>
        <div id="historySection">
            <ul class="searches" data-bind="foreach: searchTerms">
                <li class="historyItem">
                    <div class="timestamp"><span data-bind="'text': Stamp"></span></div>
                    <span data-bind="'text': Term"></span>
                </li>
            </ul>
            <a class="loadMore">Load 10 More Searches &raquo;</a>
        </div>

All of this works perfectly on everything I test, with one major exception: The WebView control for Android. Whenever I run this page there, I get the following exception:

Uncaught Error: Unable to parse bindings.
Message: ReferenceError: Stamp is not defined;
Bindings value: 'text': Stamp at {url}/Scripts/libs/knockout-2.2.1.js:5

I'm at my wit's end. I've tried every possible combination of data-bind syntax (as you can see I've tried the single quotes too, as I'd seen a post related to that at some point). My only guess now is that this might be related to my order of scripts. I do currently reference knockout before I reference jquery - could this be the issue? I hadn't seen this as an issue anywhere else, but at this point, I'm willing to try anything.

Update:

All of my other knockout binding viewModels and bindings are working fine on Android, but none of them occur on page load. So that led me to look at changing the ajax to a method and trying to delay it's calling. So I implemented the following addition to my viewmodel:

//Operations
self.loadRecent = function () {
        // Load search history
        $.ajax({
            type: "GET",
            url: "/api/history/",
            data: null,
            success: function (msg) {
                var terms = $.map(msg, function (item) { return new History(item) });
                self.history(terms);
            },
            error: function (xhr, ajaxOptions, thrownError) {
                //Error handling
            }
        });

In my page, here is what the initial binding looks like - it occurs at the bottom of the page:

var history = new HistoryViewModel();

ko.applyBindings(history, $("#historySection")[0]);
//Call page event handlers
$(window).load(function () {
    // Load in our search history
    history.loadRecent();
});

Unfortunately, same error as before. However, this is where things get really interesting. Even when I comment out the call to the loadRecent operation, I still get the error! To me, this means, for some reason, for this model only, the foreach is still trying to iterate, even though nothing exists. Do my assumptions sound correct? Anyone see anything I'm blatently missing here that would cause this issue? None of my other viewModels and views are having this issue. I have 2 others I'm binding to and they both have foreach's in them and do not seem to experience this issue.

UPDATED 2013.05.20 I updated some of the code throughout to reflect some function/object renaming I did, as I started to worry that something was getting out of sorts with me having a variable named history with a function named history (silly, I know, but I'm desparate).

I also wanted to post an additional finding. I decided to go ahead and try removing the code for loading the history completely from any loading or ready event. Rather, I was able to separate out this data load into a button click. Here is what the button click handler looks like:

 $(".menuButton").on("click", "", function () {
        history.searchTerms([]);
        history.loadRecent();
    });

Fun fact when I do this though, in Android-only. I still get an error on load, in the bindings:

 Uncaught Error: Unable to parse bindings.
 Message: ReferenceError: searchTerms is not defined;
 Bindings value: foreach: searchTerms at {url}/Scripts/libs/knockout-2.2.1.js:5

Another interesting tidbit - if I were to remove the html from the view altogether, meaning there are no bindings, yet still leave the code for the SearchTerm model and the HistoryViewModel, I still get an error from the WebView in Android, when the button is clicked:

 Uncaught TypeError: Object #<History> has no method 'searchTerms' at {url}:681

Sorry for so much posting, but I'm desperate to figure out what's wrong with this.

Mike Homol
  • 481
  • 5
  • 19
  • the android native browser is notoriously awful. do you declare all your script tags at the end of your html document? – Matthew James Davis May 16 '13 at 14:05
  • All of my inline scripts are running at the bottom, however all of my referenced .js files are being called in the header. – Mike Homol May 16 '13 at 14:24
  • try putting all of your scripts, carefully, at the very bottom. it may or may not help, just a suggestion. i've been building an app in phonegap and it works great everywhere except android gingerbread, where it is basically a webview using the native browser. – Matthew James Davis May 16 '13 at 14:29
  • okay, got everything moved to the bottom; tested it and i'm getting no errors in the browser still - exact same error as above in Droid. :( – Mike Homol May 17 '13 at 13:46
  • I made some additional findings that I'm posting above, even though I have not solved this problem, but I have gotten closer, I think and needed more space to post code updates. – Mike Homol May 17 '13 at 18:03
  • Curious, why are you using `data-bind="'text': Stamp"` instead of `data-bind="text: Stamp"` ? The extra single quotes around `text` are unnecessary. – xdumaine May 22 '13 at 12:56
  • Agreed - I found a post here on StackOverflow indicating that the Android WebView on the Gingerbread build had issues with the latter format - I had just tried it out to see if it fixed my problem in the beginning and validated that it didn't hurt anything. I intend to revoke that change, once I figure out what I've missed here. – Mike Homol May 22 '13 at 20:21

1 Answers1

0

maybe webview does some wacky stuff with HTML 5 history api and its resetting it on top of your history view model. have you tried changing the vm name to historyVM or something? i would argue you shouldnt be naming your viewmodels to match things being used by the browser itself (like, dont name your vm 'window' or 'document')

Kevin Nacios
  • 2,843
  • 19
  • 31
  • You, sir, are the man. Indeed it ended up being related to the use of either History as the model name or the use of a var named history. Either way, renaming them ended up doing the trick. Thanks so much. – Mike Homol May 28 '13 at 17:07