I have a single page app that consists of 2 main pieces:
1.-A top bar that has dynamic content(there is a shopping cart)
2.-A dynamic component that gets loaded based on the url.
A few times the components use postbox in order to communicate, the problem is that once the component itself is disposed the subscriptions created inside are not. I know I can manually add a dispose function to each component and then inside, dispose the subscriptions, but is there a way to do this in an automated way for all components?
I do know how to loop all properties and check if they are subscriptions, but I need a way to somehow attach this behavior to all components without manually attaching this dispose function to all of them.
I know postbox comes with a reset method I can call inside my routing library but I do not want to do that because then the top bar will lose its subscriptions too.
To give you some perspective, this is how the main index page looks like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Participant Dashboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<!-- styles -->
<link href="../css/bs3/bootstrap.css" rel="stylesheet">
<link href="../css/bs3/override-bs3.css" rel="stylesheet">
<script src="../scripts/global/requireConfig.js"></script>
<script data-main="../consumer/scripts/require-config" src="../scripts/require.js"></script>
</head>
<body>
<top-bar params="routeParams:currentPageArguments"></top-bar>
<div data-bind="component: { name: currentPage, params: currentPageArguments }">
</div>
</body>
</html>
This is my custom component loader:
function registerConventionLoader() {
var koNamingConventionLoader = {
getConfig: function (name, callback) {
var widgetName;
var widgetConfig = common.findComponentConfig(name);
if (widgetConfig != null) {
widgetName = name.substr(widgetConfig.Prefix.length);
var widgetNamePascalCase = common.toPascalCase(widgetName);
var filePath = widgetConfig.Path;
var viewModelConfig = {require: filePath + widgetNamePascalCase};
var templateConfig = {require: "text!" + filePath + widgetNamePascalCase + '.html'};
callback({viewModel: viewModelConfig, template: templateConfig});
}
else {
callback(null);
}
}
};
ko.components.loaders.push(koNamingConventionLoader);
}
Found it! I had to get the viewmodel from require, then attach the dispose function and finally pass it in the callback: Thanks @user3297291 for guiding me in the correct direction
var koNamingConventionLoader = {
getConfig: function (name, callback) {
var widgetName;
var widgetConfig = common.findComponentConfig(name);
if (widgetConfig != null) {
widgetName = name.substr(widgetConfig.Prefix.length);
var widgetNamePascalCase = common.toPascalCase(widgetName);
var filePath = widgetConfig.Path;
require([filePath + widgetNamePascalCase], function (mainViewModel) {
mainViewModel.prototype.dispose = function () {
var self = this;
for (var property in self) {
if (Boolean(self[property]) && typeof self[property].dispose === "function") {
self[property].dispose();
}
}
};
var templateConfig = {require: "text!" + filePath + widgetNamePascalCase + '.html'};
callback({viewModel: mainViewModel, template: templateConfig});
});
}
else {
console.log("widget name not resolved", name);
callback(null);
}
}
};
ko.components.loaders.push(koNamingConventionLoader);
}