Reputation: 2852
I have a large number of knockout components, which are currently using KO.postbox to communicate.
I now want to create a central service provider / repository / singleton which centrally stores data for and provides initialization and api and other functions for all of these components.
The page is only one window / session, but each one has 3-7 Knockout components and in some cases the same component is loaded multiple times on the page. The result is a lot of chatter between the component that has loaded data via API and those that also need the same data.
My current approach is to use the singleton pattern (other approaches happily considered). The only non-changeable requirements are:
The problem with the current code is
a. This is set to undefined by babel, e.g. this.instance = null
raises an error of cannot set instance of undefined.
b. I am not really sure this is the best method or that I can make it work
The code is below
const ko = require('knockout')
, moment = require('moment')
, postbox = require('knockout-postbox')
, aja = require('aja');
const myServiceSingleton = () =>{
this.instance = null;
this.array1 = ko.observable([]);
this.array2 = ko.observable([]);
// revealing module pattern that handles initialization of our new singleton service provider
const initializeNewModule = () => {
const setArray1 = (array) => {
console.info( 'Set Array1 Called' );
this.array1(array);
};
const getArray1 = () => {
console.info( 'Get Array1 Called' );
return this.array1();
};
const setArray2 = (array) => {
console.info( 'Set Array2 Called' );
this.array2(array);
};
const getArray2 = () => {
console.info( 'Get Array2 Called' );
return this.array2();
};
const myAwesomeFunction = () => {
// Perform some amazing computations on Array1 and Array 2
};
return {
setArray1 : setArray1,
getArray1 : getArray1,
setArray2 : setArray2,
getArray2 : getArray2,
myAwesomeFunction : myAwesomeFunction
};
};
// handles the prevention of additional instantiations
const getInstance = () => {
if( ! this.instance ) {
this.instance = new initializeNewModule();
}
return this.instance;
};
return {
getInstance : getInstance
};
};
module.exports = myServiceSingleton;
---------EDIT----------
In the hopes this helps someone else...
const ko = require('knockout')
, moment = require('moment')
, postbox = require('knockout-postbox')
, aja = require('aja');
const array1 = ko.observable([]);
const array2 = ko.observable([]);
const secretFlag = ko.observable(false);
const myAmazingSingleton = {
setArray1(newArray) {
console.info( newArray);
array1(newArray);
},
getArray1() {
console.info( 'Get Array1 Called' );
return array1();
},
getArray2() {
return array2();
},
setArray2(newArray) {
console.info('Set Array2 Called');
array2(newArray);
},
getArray1Observable() {
return array1 ;
},
myAwesomeFunction() {
// Perform some amazing computations on Array1 and Array 2
array1.map //etc etc
}
};
export default myAmazingSingleton ;
To use is quite simple:
import ArrayFunctions from 'myAmazingSingleton';
let array1 = ArrayFunctions.getArray1();
And the data is available across multiple Knockout components
Upvotes: 0
Views: 771
Reputation: 664569
You cannot use an arrow function as a constructor. You really should just use a simple object literal:
const myServiceSingleton = {
array1: ko.observable([]),
array2: ko.observable([]),
setArray1(array) {
console.info( 'Set Array1 Called' );
this.array1(array);
},
getArray1() {
console.info( 'Get Array1 Called' );
return this.array1();
},
setArray2(array) {
console.info( 'Set Array2 Called' );
this.array2(array);
},
getArray2() {
console.info( 'Get Array2 Called' );
return this.array2();
},
myAwesomeFunction() {
// Perform some amazing computations on Array1 and Array 2
}
};
If you insist, you can make an
export function getInstance() {
return myServiceSingleton;
}
or even lazy-initialise it, but usually you should just export default
it.
Upvotes: 1
Reputation: 43881
I think the singleton you want to use is a master viewmodel, by which I mean just the usual way of setting up Knockout. Use the components' params
to pass from the master viewmodel any observables that your components need to share.
Upvotes: 1