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