0
votes

I'm having this odd issue when I update my viewmodel...basically with every update, there appears to be a random chance that each observable will contain this data:

function observable() {    
        if (arguments.length > 0) {    
            // Write               

            // Ignore writes if the value hasn't changed    
            if ((!observable['equalityComparer']) || !observable['equalityComparer'](_latestValue, arguments[0])) {    
                observable.valueWillMutate();    
                _latestValue = arguments[0];    
                observable.valueHasMutated();    
            }

            return this; // Permits chained assignments    
        } else {    
            // Read    
            ko.dependencyDetection.registerDependency(observable); // The caller only needs to be notified of changes if they did a "read" operation

            return _latestValue;
        }    
    }

I've been using KnockoutJS for a while, and I've never seen anything like this. My guess is that it has something to do with my template binding, but I'm really not sure. I'm going to dig into it, but I figured I'd post it here in case anyone else is having this issue, or has a solution. Like I said, it doesn't happen consistently, only on occasion.

//// More Information ////

So Matt below referenced this (http://stackoverflow.com/questions/9763211/option-text-becomes-a-function-string-after-updated-with-fromjs), which is roughly the same issue. The only difference is that I'm using the native template binding in a style like this:

<div data-bind="template: {name: 'issueTemplate', data: incidents}"></div>

<script id="dashboardIssueTemplate" type="text/html">       
    <!--ko foreach: $data-->    
    <div data-bind="text: title"></div>
</script>

It was my assumption that KnockoutJS handled the unwrapping by itself when you pass the observableArray into the template binder. I know I can't say "title()" in this example, because that doesn't exist. Am I supposed to be binding with a command like $root.title()?

//// Even More Information ////

It appears that this problem occurs as a result of having two "applyBindings" on one page. My application contains an external widget which adds it's DOM to the host page DOM at runtime. That widget is using the ko.applyBindings(vm, ROOTNODE) syntax which should allow for the host page to run it's own ko.applyBindings(hostVm).

In fact, it does, and it works correctly every refresh. The problem however is when the host page does a viewModel update with no refresh. Somehow, the UI rendering spits out this internal function on EVERY data-bound node. I've debugged through KnockoutJS and actually confirmed that the viewModel and rootNode are correct...something outside of the actual binding is taking over.

1
if it has to do with your binding, you may want to post an example of how you're binding (preferably code where you've seen the error happen) - deltree
Agreed. A jsfiddle (jsfiddle.net) is a good way to go. - James Sulak
Ya, I normally would, but I'm deep in this project and I can't really share the code per company policy :(. I'll see if I can't get it reproduced in jsfiddle. - farina
Actually, I'm thinking this may have more to do with my other question [stackoverflow.com/questions/9775073/… It seems to happen the instant the new data comes into the observable array after I've cleared it out. I think I'm going to play with the mapping plugin and see how to do this properly. - farina
Nevermind...doesn't look like the mapping plugin does what I need because it actually replaces the entire viewmodel. I thought it just created an observableArray :(. - farina

1 Answers

1
votes

This has something to do with the "()" appended onto the data object in the template. What I've found is that during the first render (page load) writing the template like this:

<div data-bind="template: {name: 'issueTemplate', data: incidents}"></div>

<script id="dashboardIssueTemplate" type="text/html">       
    <div data-bind="text: title"></div>
</script>

works just fine. However, once you run the update on the observableArray my "title" object becomes that function. If I write the template using this style:

<div data-bind="text: title()"></div>

It seems to work on every update.

I am not certain why this is the solution. From the looks of it, the data object being passed to the Knockout binder is the exact same on both page load and update. I'll post this as an answer, but I'm not marking it as an answer until I understand why this is happening.