Reputation: 233
When I searched,I found,how to bind values from viewmodel to view but not viewmodel to viewmodel I have a requirement to pass one property value from one viewmodel to another viewmodel as I need the initial property to be updated in first viewmodel then I want to use it in another viewmodel.because it is helpful while testing.
Assume that the below view model is the 1st view model,
var xx = xx || {};
xx.yyy = xx.yyy || {};
xx.yyy.zzz = function(object ) {
var model = {};
model.isTested= ko.observable(false);
//below is the anonymous call to get the value(true/false):
datasource.someFeatureEnable.isTested().done(function (featureToggle) {
model.isTested(featureToggle.enabled);
});
}
I want to pass isTested(true/false) property value in another viewmodel because to run my application properly and make my tests pass
Upvotes: 3
Views: 4126
Reputation:
It would depend on whether the two viewmodels are in memory and available at the same time. If so, then scaryman's suggestion of using knockout-postbox is a good one. Or, you could use a client-side message bus such as postal.js (which is what I use).
If the viewmodels are not in memory and available at the same time, then introducing a third, static object (we'll call it "Z") would be necessary to handle something similar to an Event Aggregator pattern. Essentially, viewmodel-1 would directly reference Z to store the isTested
value there. When viewmodel-2 instantiates, it would check with Z to get the isTested
value. This approach is not really an aggregation of events since you're not publishing messages on a channel (although, if you were to take the approach of sending messages with payload to Z, then it would be--way more complicated than it needs to be in this case).
If you're using AMD--say, require--you would simply require Z in each of your viewmodels (or, actually, in every viewmodel dependent upon Z). You can read about require at http://www.requirejs.org.
Bare bones, we would have:
viewmodel-1
this.isTested = ko.observable(false);
var Z = require("Z");
Z.isTested(this.isTested());
viewmodel-2
this.isTested = false; //Making the assumption that isTested doesn't have to be observable here--but it could be
var Z = require("Z");
this.isTested = Z.isTested();
Of course, you would elaborate on this so that Z could handle an array of viewmodels, perhaps with a dictionary object that could look up the viewmodel in question.
I would caution against scaryman's approach, though, of making viewmodels dependent on each other. If you have many viewmodels that have an isTested
relationship, the dependency graph could get pretty hairy. I would concentrate isTested
and perhaps other properties in one, third-party module: Z.
I would reiterate that Z should be static. That means it should return an object literal, not a constructor function.
As a final note, I'm not suggesting the Mediator pattern, by the way. I'm not suggesting that Z should store references to each of viewmodel-1 and viewmodel-2.
Upvotes: 0
Reputation: 1900
You could make your second viewmodel have a dependency on your first viewmodel.
//this is the definition of your first view model.
function MainViewModel(dataSource) {
var self = this;
this.DataSource = dataSource;
this.isTested = ko.observable(false);
//a callable function that will run isTested check on someFeatureEnable
this.TestSomeFeature = function() {
self.DataSource.someFeatureEnable.isTested().done(function (featureToggle) {
self.isTested(featureToggle.enabled);
});
};
return this;
}
//this is the definition of your second viewmodel
function SubViewModel(mainViewModel) {
var self = this;
self._mainViewModel = mainViewModel;
//for read only access
self.MainIsTested = function() { return self._mainViewModel.isTested(); }
//for read/write
self.MainIsTestedReference = self._mainViewModel.isTested
return self;
}
//this is the code that initializes the whole page.
var main = new MainViewModel();
var sub = new SubViewModel(main);
//now run the check
main.TestSomeFeature();
//these are examples, showing how to get at the isTested property in your various viewmodels. The comments are what the code should return
sub.MainIsTested(); //false
main.isTested(); //false
//set isTested to true from the sub
sub.MainIsTestedReference(true);
//now main isTested returns true, because the sub viewmodel and the main viewmodel have references to the same object.
main.isTested(); // true
If you want to get more advanced and use an events based approach I'd recommend looking into ko.postbox, check out these references.
http://www.knockmeout.net/2012/05/using-ko-native-pubsub.html
https://github.com/rniemeyer/knockout-postbox
Upvotes: 3
Reputation: 17564
I would use a event aggregator pattern, this is a decoupled and powerfull way for any listener to listen to any event without couppling to the publisher.
You can check how I did that for this library (SignalR library)
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/
I extracted the client side only code for your convenience
basicly what you do to pub / sub is
signalR.eventAggregator.subscribe(Event, listener.onEvent, listener);
setInterval(function() {
signalR.eventAggregator.publish(new Event(new Date()));
}, 500);
setTimeout(function() {
signalR.eventAggregator.unsubscribe(listener);
}, 5000);
Upvotes: -1