Preferred way to clear/delete all previous bindings/observables on viewmodel

3,405 views
Skip to first unread message

Henning Skoglund

unread,
Jan 29, 2013, 11:54:13 AM1/29/13
to knock...@googlegroups.com
hi, i am writing a single page application to view .FIT files from Garmin. At the moment i am struggelig with just clearing all observables on the viewmodel. What is the preferred way of clearing/deleting all observables on  the viewmodel (I use the mapping plugin to convert JSON)? I've tried ko.cleanNode/ko.removeNode, but it doesnt work.

My code is :

if (FITUI.sessionViewModel === undefined) {
                   
// http://stackoverflow.com/questions/10048485/how-to-clear-remove-observable-bindings-in-knockout-js
                   
                    FITUI
.sessionViewModel = ko.mapping.fromJS(rawData.session, mappingOptions);
                   
                    ko
.applyBindings(FITUI.sessionViewModel, sessionElement); // Initialize model with DOM
               
}
               
else {
                   
// Need to clean the viewmodel and update UI....but how???
                   
//  Attemps so far:
                   
// FITUI.sessionViewModel.mappedDestroyAll();
                   
//for (var observableArray in FITUI.sessionViewModel)
                   
//    observableArray().removeAll();
                   
// ko.cleanNode(sessionElement);
                   
// cleanSessionObservableArrays(FITUI.sessionViewModel);

                    ko.mapping.fromJS(rawData.session, mappingOptions, FITUI.sessionViewModel); // Just update model with new data
               
}

Michael Latta

unread,
Jan 29, 2013, 12:31:42 PM1/29/13
to knock...@googlegroups.com
I think you are looking at the problem wrong.  You do not "clear" observables from a view model.  Once you do an applyBindings those observables remain and are reused to connect to the DOM.  The mapping plugin will update existing observables or create new ones as needed to represent the data.  You only call applyBindings once per page load.

Michael

--
You received this message because you are subscribed to the Google Groups "KnockoutJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to knockoutjs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

lei...@gmail.com

unread,
Jan 29, 2013, 2:34:07 PM1/29/13
to knock...@googlegroups.com
There are a couple ways to interpret what you may be trying to accomplish:
1) you have an exsting viewmodel, bound to active, displayed DOM elements, and you want to replace their values with those from another data record
2) you have want to replace your current DOM elements with new ones tied to another data record

For (1), it may be as simple as calling ko.mapping.fromJS()--unless there are values the new data may not include, leaving stale ones from the old value intact. In this case, you could simply write a recursive method to assign null/""/0/[] to all observables in your viewmodel before calling ko.mapping.fromJS() with new data.

For (2), this is the really easy case--you just instantiate a new viewmodel instance and use the template engine to add it to the DOM, or assign it wholesale as the value of an observable in your root viewmodel. KO will take care of everything.

eg: function rootViewModel() {
    this.currentValue = observable();
}

vm = new rootViewModel();
vm.currentValue(new OtherViewModel(newlyFetchedData));

<div data-bind="with: currentValue">
  <!-- stuff that uses properties from OtherViewModel -->
</div>

Henning Skoglund

unread,
Jan 29, 2013, 5:07:18 PM1/29/13
to knock...@googlegroups.com, lei...@gmail.com
I went with your (1) option and wrote a function to set observableArrays to []. The rawdata object can have a varying numbers of observable arrays attached.

resetViewModel = function (viewModel) {
           
// Set arrays to []
           
for (var observableArray in viewModel) {


               
if (observableArray !== "__ko_mapping__" && viewModel[observableArray].removeAll) {
                 
//  console.log("RemoveAll() on ", observableArray);
                    viewModel
[observableArray].removeAll();
               
}
           
}
       
}

//on new raw data from file:

resetViewModel
(FITUI.sessionViewModel);
ks
.mapping.fromJS(...)

Thanks.

lei...@gmail.com

unread,
Jan 29, 2013, 5:12:54 PM1/29/13
to knock...@googlegroups.com
This seems like it could be a common-enough use case to merit enhancing ko.mapping.fromJS()--the case where the data may not always be of the same structure.

I think it would be good for there to be an option to tell fromJS() to produce a result identical to what an initial call to mapping would have produced with the same data--pruning arrays/emptying observables for elements not present in the new data--but reusing existing observables which are likely bound to DOM elements in the display.

Michael Latta

unread,
Jan 29, 2013, 6:24:26 PM1/29/13
to knock...@googlegroups.com
If you have varying structure in the incoming data mapping that to the DOM can be problematical unless you are using separate templates for each data set.  In that case it is easier to have an intermediate object that gets replaced and drives the new DOM as well as providing a new place to hold the data.

var newRoot = ko.mapping.fromJS(data);
ViewModel.rootObject(newRoot);

Then you use a "with" binding to get relative to the root, use a template binding with data set to the rootObject, etc.

Then each new root object will be a clean canvas for mapping but the DOM will adjust to the new object as needed.  You can even select the template type based on a value in the new root object.

Michael




On Jan 29, 2013, at 3:12 PM, lei...@gmail.com wrote:

This seems like it could be a common-enough use case to merit enhancing ko.mapping.fromJS()--the case where the data may not always be of the same structure.

I think it would be good for there to be an option to tell fromJS() to produce a result identical to what an initial call to mapping would have produced with the same data--pruning arrays/emptying observables for elements not present in the new data--but reusing existing observables which are likely bound to DOM elements in the display.


Reply all
Reply to author
Forward
0 new messages