oracle-databasedynamicknockout.jsbindingoracle-jet

Dynamically Binding the the Oracle jet switcher slot to the oracle jet add and remove tab(Make switcher slot dynamic in oracle jet)


I want to make tab switcher auto decide the slot for the switcher but when I am trying to make it dynamic with the help of observable no data is showing the tab content area until I write the slot area statically. With observable variable, the slot is not getting the selected Slot value.

Please check how I can do this.

slot = [[selectedSlot]] //using for the slot value in html

this.selectedSlot = ko.observable('settings');

<div id="tabbardemo">
 <oj-dialog class="tab-dialog hidden" id="tabDialog" dialog-title="Tab data">
              <div slot="body">
                <oj-form-layout>
                  <oj-input-text id="t1" value="{{newTabTitle}}" label-hint="Title"></oj-input-text>
                </oj-form-layout>
              </div>
          
              <div slot="footer">
                <oj-button id="idOK" on-oj-action="[[addTab]]">OK</oj-button>
                <oj-button id="idCancel" on-oj-action="[[closeDialog]]">Cancel</oj-button>
              </div>
            </oj-dialog>
          
            <oj-button id="addTab" on-oj-action="[[openDialog]]">Add Tab</oj-button>
            <br/>
            <br/>
          
            <oj-tab-bar contextmenu="tabmenu" id="hnavlist" selection="{{selectedItem}}" current-item="{{currentItem}}" edge="top" data="[[dataProvider]]"
              on-oj-remove="[[onRemove]]">
              <template slot="itemTemplate" data-oj-as="item">
                <li class="oj-removable" :class="[[{'oj-disabled' : item.data.disabled}]]">
                  <a href="#">
                    <oj-bind-text value="[[item.data.name]]"></oj-bind-text>
                  </a>
                </li>
              </template>
              <oj-menu slot="contextMenu" class="hidden" aria-label="Actions">
                <oj-option data-oj-command="oj-tabbar-remove">
                  Removable
                </oj-option>
              </oj-menu>
            </oj-tab-bar>
            
             <oj-switcher value="[[selectedItem]]">
                <div slot="[[selectedSlot]]"
                     id="home-tab-panel"
                     role="tabpanel" 
                     aria-labelledby="home-tab">
                  <div class="demo-tab-content-style">
                    <h2>Home page content area</h2>
                  </div>
                </div>
                <div slot="tools"
                          id="tools-tab-panel"
                          role="tabpanel" 
                          aria-labelledby="tools-tab">
                  <div class="demo-tab-content-style">
                    <h1>Tools Area</h1>
                    </div>
                  </div>  

                <div slot="base"
                     id="base-tab-panel"
                     role="tabpanel" 
                     aria-labelledby="ba`enter code here`se-tab">
                  <div class="demo-tab-content-style">
                    <h1>Base Tab</h1>
                    </div>
                  </div>
              </oj-switcher>
          
            <br>
            <div>
              <p class="bold">Last selected list item:
                <span id="results">
                  <oj-bind-text value="[[selectedItem]]"></oj-bind-text>
                </span>
              </p>
            </div>
          </div>

JS code below

require(['ojs/ojcontext',
      'knockout',
      'ojs/ojbootstrap',
      'ojs/ojarraydataprovider',
      'ojs/ojknockout',
      'ojs/ojnavigationlist',
      'ojs/ojconveyorbelt',
      'ojs/ojdialog',
      'ojs/ojbutton',
      'ojs/ojinputtext',
      'ojs/ojformlayout',
      'ojs/ojswitcher',
    ],
      function (Context, ko, Bootstrap, ArrayDataProvider) { // this callback gets executed when all required modules are loaded
        function ViewModel() {
          this.data = ko.observableArray([{
            name: 'Settings',
            id: 'settings'
          },
          {
            name: 'Tools',
            id: 'tools'
          },
          {
            name: 'Base',
            id: 'base'
          }
                                         ]);
          this.selectedSlot = ko.observable('settings'); //Sepecifically mentioned to show what it is the objective
          
          this.dataProvider = new ArrayDataProvider(this.data, { keyAttributes: 'id' });
          this.selectedItem = ko.observable('settings');
          this.currentItem = ko.observable();
          this.tabCount = 0;
          this.newTabTitle = ko.observable();
  
          this.delete = (function (id) {
            var hnavlist = document.getElementById('hnavlist');
            var items = this.data();
            for (var i = 0; i < items.length; i++) {
              if (items[i].id === id) {
                this.data.splice(i, 1);
                Context.getContext(hnavlist)
                  .getBusyContext()
                  .whenReady()
                  .then(function () {
                    hnavlist.focus();
                  });
                break;
              }
            }
          }).bind(this);
  
          this.onRemove = (function (event) {
            this.delete(event.detail.key);
            event.preventDefault();
            event.stopPropagation();
          }).bind(this);
  
          this.openDialog = (function () {
            this.tabCount += 1;
  
            this.newTabTitle('Tab ' + this.tabCount);
            document.getElementById('tabDialog').open();
          }).bind(this);
  
          this.closeDialog = function () {
            document.getElementById('tabDialog').close();
          };
  
          this.addTab = (function () {
            var title = this.newTabTitle();
            var tabid = 'tid' + this.tabCount;
            this.data.push({
              name: title,
              id: tabid
            });
            this.closeDialog();
          }).bind(this);
        }
  
        Bootstrap.whenDocumentReady().then(function () {
          ko.applyBindings(new ViewModel(), document.getElementById('tabbardemo'));
        });
      }
    );

Solution

  • It is a bit complex to understand when you copy from JET cookbook. You have done almost everything right. Just make the following changes:

    1) Remove this:

    Bootstrap.whenDocumentReady().then(function () {
              ko.applyBindings(new ViewModel(), document.getElementById('tabbardemo'));
            });
    

    Why? The bootstrapping is required once per application, which is done inside your main.js file.

    2) Replace require by define Why? Require block is again maintained in main.js, where your required modules are pre-loaded. All subsequent viewModels have define block

    3) Return an instance of your ViewModel

    define([
    ... Your imports
    ],
    function (Context, ko, Bootstrap, ArrayDataProvider) { // this callback gets executed when all required modules are loaded
      function ViewModel() {
            // Your code
       }
       return ViewModel;
    });