OJET: Inter-Module communication in TypeScript Template
In this post I bring another example on how to Communicate Modules using the Oracle JET - TypeScript Template based on the Oracle JET Cookbook: InterModule Communication
From now and so on will create multiple examples using TypeScript for those who are not familiar with it and wants to turn the Cookbook examples into TypeScript :).
The example (ojet-typescript-list-detail) can be found as usual in my GitHub repository:
https://github.com/DanielMerchan/ojet-examples
This example is a bit different compared to the Cookbook example where the modules are not running at the same time within a Module.
This example is built as described in the following images:
customers/list.js
customers/detail.js
From now and so on will create multiple examples using TypeScript for those who are not familiar with it and wants to turn the Cookbook examples into TypeScript :).
The example (ojet-typescript-list-detail) can be found as usual in my GitHub repository:
https://github.com/DanielMerchan/ojet-examples
This example is a bit different compared to the Cookbook example where the modules are not running at the same time within a Module.
This example is built as described in the following images:
- Customers module acts as the Wrapper Module. It coordinates when to load the list and detail modules.
- Customers module makes use also of signals npm module for communication between Customers-List, Customers-Detail.
Explanation of the Example
- customers.js is the coordinator responsible module for:
- initializes and controls the Customers Data Model.
- Send the necessary data to list and detail module by ViewModel params.
- customers.js uses signals npm module to send and listen the following events
- customerSelectedSignal: When a customer is selected in the list module, the customerId is send to customers module to load the detail module passing the customerId selected.
- backToListSignal: Within the detail module, there is a button to navigate back to the list module. The detail module sends a signal (fires an event) to notify the customers module to navigate back to the list module.
import * as ko from "knockout";
import { ojModule } from 'ojs/ojmodule-element';
import Utils = require('../Utils');
import Router = require('ojs/ojrouter');
import signals = require("signals");
import "ojs/ojknockout";
import Customer = require('../model/Customer');
/**
* CustomersViewModel module which uses two auxiliar modules for list / detail visualization of Customers
* @author Daniel Merchan Garcia
* @version 6.2.0
*/
class CustomersViewModel {
// Attributes
router: Router;
custChildRouter: Router;
moduleConfig: KnockoutObservable<ojModule['config']>;
customerSelectedSignal: signals.Signal;
backToListSignal: signals.Signal;
static customers: Array<Customer>;
currentChildSelection: KnockoutObservable<string>;
// Static Methods
static initializeCustomers() {
CustomersViewModel.customers = [{ id: 0, name: 'Paco', age: 22 }, { id: 1, name: 'Eva', age: 30 }];
}
/**
* Default Constructor of the Customers View Model
* It is used as a container / wrapper of the List / Detail Modules
*/
constructor() {
let self = this;
// Router
self.router = Router.rootInstance;
// Parameters to be passed to the child modules
self.customerSelectedSignal = new signals.Signal();
self.backToListSignal = new signals.Signal();
// Default Module Configuration
let defaultConfig: ojModule['config'] = { view: [], viewModel: Object, cleanupMode: "onDisconnect" };
self.moduleConfig = ko.observable(defaultConfig);
// Build default Child Module Configuration based on the Child Router State
self.custChildRouter = self.router.getCurrentChildRouter() as Router;
self.loadCustomerModule(self.custChildRouter.moduleConfig.name());
// Signals Listeners
// Listen when a customer has been selected in the 'list' module
self.customerSelectedSignal.add(customerId => {
self.custChildRouter.go(`detail/${customerId[0]}`).then(status => {
if (status.hasChanged) {
self.loadCustomerModule(self.custChildRouter.moduleConfig.name());
}
});
});
// Listen when 'back to list' is clicked in a 'detail' module
self.backToListSignal.add(() => {
self.custChildRouter.go(`list`).then(status => {
if (status.hasChanged) {
self.loadCustomerModule(self.custChildRouter.moduleConfig.name());
}
});
})
}
// Custom Functions
private loadCustomerModule(name: string): void {
let data = {};
if (name === 'detail') {
const mc = this.custChildRouter.observableModuleConfig();
const customerId = mc.params['ojRouter']['parameters']['id']();
data = { 'backToListSignal': this.backToListSignal, 'customers': CustomersViewModel.customers, 'customerId': customerId };
} else {
data = { 'customerSelectedSignal': this.customerSelectedSignal, 'customers': CustomersViewModel.customers };
}
Utils.resolveViewAndViewModel(this.router.moduleConfig.name() + '/' + name, this.moduleConfig, 'none', data);
}
/*
* Optional ViewModel method invoked after the View is inserted into the
* document DOM. The application can put logic that requires the DOM being
* attached here.
* This method might be called multiple times - after the View is created
* and inserted into the DOM and after the View is reconnected
* after being disconnected.
*/
connected(): void {
// Implement if needed
};
/**
* Optional ViewModel method invoked after the View is disconnected from the DOM.
*/
disconnected(): void {
let self = this;
self.customerSelectedSignal.removeAll();
self.backToListSignal.removeAll();
};
/**
* Optional ViewModel method invoked after transition to the new View is complete.
* That includes any possible animation between the old and the new View.
*/
transitionCompleted(): void {
// Implement if needed
};
}
// Initialize static content
CustomersViewModel.initializeCustomers();
export = CustomersViewModel;
customers/list.js
import signals = require('signals');
import Customer = require('../../model/Customer');
import ArrayDataProvider = require('ojs/ojarraydataprovider');
import { ojListView } from 'ojs/ojlistview';
import 'ojs/ojlistview';
/**
* ViewModel for the List Module wrapped by the Customer Module
* @author Daniel Merchan Garcia
* @version 6.2.0
*/
class CustomersListViewModel {
customerSelectedSignal: signals.Signal;
customers: Array<Customer>;
customersArrayDataProvider: ArrayDataProvider<Array<Customer>,object>;
onSelectCustomer: ojListView<string,object>['onSelectionChanged'];
/**
* Constructor
* Takes the customersList as parameters.
* For Demo purposes, all customers is loaded in a demo JSON Array.
*
* @constructs CustomersDetailViewModel
*
* @fires CustomersViewModel#backToListSignal
* @param {any} params Parameters sent by the Customer Wrapper Module
*
*/
constructor(params: any) {
let self = this;
self.customerSelectedSignal = params.customerSelectedSignal;
self.customers = params.customers;
self.customersArrayDataProvider = new ArrayDataProvider(self.customers, {keyAttributes: 'id'});
self.onSelectCustomer = event => {
self.customerSelectedSignal.dispatch(event.detail.value);
}
}
/**
* Optional ViewModel method invoked after the View is inserted into the
* document DOM. The application can put logic that requires the DOM being
* attached here.
* This method might be called multiple times - after the View is created
* and inserted into the DOM and after the View is reconnected
* after being disconnected.
*/
connected(): void {
// Implement if needed
};
/**
* Optional ViewModel method invoked after the View is disconnected from the DOM.
*/
disconnected(): void {
// Implement if needed
};
/**
* Optional ViewModel method invoked after transition to the new View is complete.
* That includes any possible animation between the old and the new View.
*/
transitionCompleted(): void {
// Implement if needed
};
}
export = CustomersListViewModel;
customers/detail.js
import { ojButton } from 'ojs/ojbutton';
import 'ojs/ojbutton';
import 'ojs/ojtoolbar';
import 'ojs/ojlabel';
import signals = require('signals');
import Customer = require('src/ts/model/Customer');
import * as ko from "knockout";
/**
* ViewModel for the Detail Module wrapped by the Customer Module
* @author Daniel Merchan Garcia
* @version 6.2.0
*/
class CustomersDetailViewModel {
// Attributes
backButtonAction: ojButton['onOjAction'];
backToListSignal: signals.Signal;
customerSelected: KnockoutObservable<Customer>;
/**
* Constructor
* Takes the customerId and the customersList as parameters.
* For Demo purposes, we use a set of Data loaded directly in memory.
*
* @constructs CustomersDetailViewModel
*
* @fires CustomersViewModel#backToListSignal
* @param {any} params Parameters sent by the Customer Wrapper Module
*
*/
constructor(params: any) {
let self = this;
self.backToListSignal = params.backToListSignal;
const customers = params.customers;
const customerId = params.customerId;
self.customerSelected = ko.observable(customers[customerId]);
self.backButtonAction = (_event: ojButton.ojAction) => {
this.backToListSignal.dispatch();
}
}
/**
* Optional ViewModel method invoked after the View is inserted into the
* document DOM. The application can put logic that requires the DOM being
* attached here.
* This method might be called multiple times - after the View is created
* and inserted into the DOM and after the View is reconnected
* after being disconnected.
*/
connected(): void {
// Implement if needed
};
/**
* Optional ViewModel method invoked after the View is disconnected from the DOM.
*/
disconnected(): void {
// Implement if needed
};
/**
* Optional ViewModel method invoked after transition to the new View is complete.
* That includes any possible animation between the old and the new View.
*/
transitionCompleted(): void {
// Implement if needed
};
}
export = CustomersDetailViewModel;


I just want to thank you for sharing your information and your site or blog this is simple but nice Information I’ve ever seen i like it i learn something today. BPMN
ReplyDeleteKnockoutObservable is throwing compile time error
ReplyDelete