javascript - Why are these Knockout subscriptions notifying an object that shouldn't have subscriptions at all -
check out here:jsfiddle
here's html:
<script src="http://code.jquery.com/jquery-2.1.4.min.js" ></script> <div id="first"> <button data-bind="click: togglecolumn">click me!</button> </div> <ul id="list_test"> <!-- ko foreach: list --> <li data-bind="text: $data.colname"></li> <!-- /ko --> </ul>
here's javascript:
function viewmodel(){ var self = this; self.showcolumn = ko.observable(true); self.togglecolumn = function(){ self.showcolumn(!self.showcolumn()); }; self.listofobjects = [ {colname: 'test1', visible: self.showcolumn}, {colname: 'test2'}, {colname: 'test3', visible: self.showcolumn}, {colname: 'test4'}, {colname: 'test5'}, ]; }; function testviewmodel(params){ var self = this; self.list = ko.observablearray(); for(var = 0; < params.length; i++){ var obj = params[i]; if(!obj.visible){ //obj.visible = ko.observable(true); } if(obj.visible){ obj.visible.subscribe(function(){ var elements = $('li'); for(var = 0; < elements.length; i++){ if($(elements[i]).text() == obj.colname){ $(elements[i]).hide(); } } }); } self.list.push(obj); } } function initviewmodel(){ var mod = new viewmodel(); ko.applybindings(new testviewmodel(mod.listofobjects),document.getelementbyid("list_test")); ko.applybindings(mod, document.getelementbyid("first")); } initviewmodel();
so issue this. why when click button, 'test5' list item gets hidden , not 2 subscribed objects (test1 , test3)? seems default hiding end of list.
i've done actual code, since jsfiddle barebone replication of error, , examined through chrome's console / debugger.
within subscribe call, obj.visible property when compared showcolumn variable not same instance. if getsubscriptionscount on obj.visible inside subscribe call 1 subscription should never have gotten in first place because never should have been defined. if on 'test1' , 'test3' visible properties 2 subscriptions (as expected) , references same instance viewmodel.showcolumn.
still within subscribe call, if check value of obj, you'll get
{colname: 'test5', visible: /*some knockout obj*/}
it never should have called subscribe 'test5'. should have called 'test1' , 'test3'.
now, how obj.visible.subscribe notified 'item5' when 'item5' object never received reference viewmodel.showcolumns? how possible visible defined 'item5'?
to me, looks subscribe on different ko.observable object notifying subscribe on different (non-existent even) ko.observable. i'm pretty sure shouldn't happening...
that's classic "closure" bug. obj
variable changing during life of for
loop, , last value holds points "test5". event handler function uses same variable, when event fired, looks "test5" , hides that. can solve standard closure & iife.
here's important code:
if(obj.visible){ (function (obj) { obj.visible.subscribe(function(){ var elements = $('li'); for(var = 0; < elements.length; i++){ if($(elements[i]).text() == obj.colname){ $(elements[i]).hide(); } } }); })(obj); }
here's fixed fiddle.
Comments
Post a Comment