JavaScript Application Development API for Oracle Visual Builder Cloud Service - Classic Applications

Source: viewmodel/js/api/Archetype.js

define([
    'module'
], function (
    module
    ) {

    'use strict';

    /**
     * View model support for work with Business Objects (BO) providing higher-level
     * BO related operations and building blocks for complex UIs such as forms,
     * collections, charts and others.
     *
     * <p>Data driven applications consist of handful of patterns and behaviours
     * which keep repeating again and again. ABCS recognizes this and provides
     * for each of these patterns an abstraction called "archetype". The goal of
     * archetype is to:</p>
     *
     * <ul>
     * <li>hide low level repetitive programming details</li>
     * <li>provide building blocks which describe application semantic and its purpose</li>
     * <li>separate UI (which changes in time) from application business logic (which is fairly set)</li>
     * <li>support rapid application building</li>
     * </ul>
     *
     * <p>The claim which ABCS makes is that any data driven application can be
     * described using the archetypes architecture. That is, core of any data
     * driven application is primarily about querying data, displaying data,
     * capturing data.</p>
     *
     * <p>Archetypes that are part of a page are generated into its {@link viewmodel/js/api/PageViewModel view model}
     * where you may access them as e.g. <code>pageViewModel.Archetypes.customerTableArchetype</code>.</p>
     *
     * <p><strong>Note that</strong> archetypes may not be present on a page indefinitely.
     * As their owner component (such as table, list or a form) may be removed
     * from the page, so may the archetype be removed along with it. Hence you
     * should always check for the archetype's existence before using it:</p>
     * <pre>
     * var archetype = pageViewModel.Archetypes.customerTableArchetype;
     * if (archetype) {
     *     // do something with the archetype
     * }
     * </pre>
     *
     * <p>Known implementations of <code>Archetype</code> are:</p>
     * <dl>
     * <dt>{@link viewmodel/js/api/CollectionArchetype CollectionArchetype}</dt>
     * <dd>Solves use-cases related to work with collection of data
     * and collection components (table or list).</dd>
     * <dt>{@link viewmodel/js/api/DetailArchetype DetailArchetype}</dt>
     * <dd>Solves use-cases related to work with a single record and
     * a form component.</dd>
     * </dl>
     *
     * @AbcsAPI stable
     * @version 16.3.5
     * @exports viewmodel/js/api/Archetype
     *
     * @constructor
     * @private
     * @param {Entity} entity
     * @param {Object} archetypeJSON - JSON description (metadata) of the underlying archetype
     * @see {@link viewmodel/js/api/CollectionArchetype CollectionArchetype} for archetype
     * working with collection of records.
     * @see {@link viewmodel/js/api/DetailArchetype DetailArchetype} for archetype
     * working with a single record.
     * @see {@link viewmodel/js/api/PageViewModel PageViewModel} to see how to access
     * archetype instances in a page.
     */
    /*
     * Archetype constructor is guaranteed to be called only once when page
     * owning it is created for the first time. Any initialization which is
     * independent of page state should be performed here.
     */
    var Archetype = function(entity, archetypeJSON) {
        AbcsLib.checkThis(this);

        this._entity = entity;
        this._entityName = entity ? entity.getName() : AbcsLib.i18n('viewmodel.missingBusinessObjectName');
        if (entity) {
            this._entityId = entity.getId();
        }
        this._observables = {};

        if (archetypeJSON) {
            var id = archetypeJSON.id;

            this._id = id;

            // Check also for archetypeJSON.archetype for backward compatibility
            this._type = archetypeJSON.type ? archetypeJSON.type : archetypeJSON.archetype;
            this._entityId = this._entityId || archetypeJSON.entityId;
            if (!this._entity) {
                Archetype._LOGGER.error('Incomplete archetype initialization, nonexistent entity with ID: ' + this._entityId);
            }
        }
    };

    Archetype._LOGGER = Logger.get(module.id);

    /**
     * Returns archetype's ID.
     *
     * The ID is unique inside an ABCS page, not across whole ABCS application.
     *
     * @AbcsAPI stable
     * @version 16.3.5
     * @returns {String}
     */
    Archetype.prototype.getId = function() {
        AbcsLib.checkParameterCount(arguments, 0);
        return this._id;
    };

    /**
     * Returns {@link viewmodel/js/api/ArchetypeType type} of the archetype.
     *
     * Type defines the archetype's behaviour, methods, fields and observables.
     * Currently known types are:
     * <ul>
     * <li>{@link viewmodel/js/api/ArchetypeType.COLLECTION ArchetypeType.COLLECTION} identifies a
     * {@link viewmodel/js/api/CollectionArchetype CollectionArchetype} working
     * with collections.
     * <li>{@link viewmodel/js/api/ArchetypeType.ENTITY_DETAIL ArchetypeType.ENTITY_DETAIL} identifies a
     * {@link viewmodel/js/api/DetailArchetype DetailArchetype} working with single record.
     * </ul>
     *
     * @AbcsAPI stable
     * @version 16.3.5
     * @returns {viewmodel/js/api/ArchetypeType}
     */
    Archetype.prototype.getType = function() {
        AbcsLib.checkParameterCount(arguments, 0);
        return this._type;
    };

    /**
     * Returns entity instance this archetype is bound to.
     *
     * <p><strong>Note</strong> that there are cases when this may be <code>undefined</code>,
     * such as when the entity is not found in the data model.</p>
     *
     * @AbcsAPI stable
     * @version 16.3.5
     * @returns {entity/js/api/Entity} entity the archetype is bound to. In special
     * occassions when the archetype is broken this may return <code>undefined</code>.
     * @example <caption>List all Business Objects in all page archetypes and
     * print their names.</caption>
     * // expecting you have an instance of a page view model assigned to 'self'
     * // as this will often be the case in business actions code.
     * var pageViewModel = self;
     * var archetypeIds = Object.keys(pageViewModel.Archetypes);
     * archetypeIds.forEach(function (archetypeId) {
     *     // get instance of bound entity for an archetype
     *     var entity = pageViewModel.Archetypes[archetypeId].getEntity();
     *     // you should always check if the value is defined as in rare cases
     *     // the archetype may not give you the reference to its entity
     *     if (entity) {
     *         // print its name
     *         console.log('Page contains an archetype with BO: ' + entity.getName());
     *     }
     * });
     */
    Archetype.prototype.getEntity = function() {
        AbcsLib.checkParameterCount(arguments, 0);
        return this._entity;
    };

    Archetype.prototype.getEntityId = function() {
        return this._entityId;
    };

    Archetype.prototype.getEntityName = function() {
        return this._entityName;
    };

    /**
     * Returns an object that contains a set of fields and observables you can
     * bind to in your components and use to communicate with other components on
     * a page bound to the same instances.
     *
     * The content of the object is described in specific archetype instances:
     * <ul>
     * <li>{@link viewmodel/js/api/CollectionArchetype#getObservables CollectionArchetype}</li>
     * <li>{@link viewmodel/js/api/DetailArchetype#getObservables DetailArchetype}</li>
     * </ul>
     *
     * @AbcsAPI stable
     * @version 16.3.5
     * @returns {Object} observables exposed by the archetype
     * @see {@link viewmodel/js/api/CollectionArchetype#getObservables CollectionArchetype} to see
     * an example and description of what collection archetype's method returns.
     * @see {@link viewmodel/js/api/DetailArchetype#getObservables DetailArchetype} to see
     * an example and description of what detail archetype's method returns.
     */
    Archetype.prototype.getObservables = function() {
        AbcsLib.checkParameterCount(arguments, 0);
        return this._observables;
    };

    /**
     * Called by {@link ViewModelDefinition} once all archetypes are initialized.
     *
     * <p>
     * This allows particular subclasses initiate their references if there are any.
     * </p>
     *
     * @param {Object} archetypeJSON - archetype descriptor in JSON format
     * @param {Archetype[]} archetypes - list of all archetypes from the viewmodel
     */
    Archetype.prototype.setUpReferences = function(/*archetypeJSON, archetypes*/) {
    };

    /**
     * To be subclassed.
     *
     * @param {string} piece of document fragment to restore the page model state.
     */
    Archetype.prototype.getBookmark = function() {
    };

    /**
     * Called upon page opening to allow archetype to updated itself based
     * on context in which the page is being opened. This method is called
     * as a result of Navigation.navigateToPage call. See also updateViewModel.
     *
     * @param {ContextualData} contextualData
     */
    Archetype.prototype.createViewModel = function(contextualData) {
        this._contextualData = contextualData;
    };

    /**
     *
     * @returns {ContextualData}
     */
    Archetype.prototype.getContextualData = function() {
        return this._contextualData;
    };

    /**
     * Called upon returning to an already opened page to allow archetype to
     * update itself based on changes represented in updateContextualData. This
     * method is called as a result of Navigation.returnToPage call. See also
     * createViewModel.
     *
     * <p>To be implemented by descendants based on their needs.</p>
     *
     * @param {ContextualData} contextualData
     */
    Archetype.prototype.updateViewModel = function(/*contextualData*/) {
    };

    Archetype.prototype.getDefinition = function () {
        var def = {};
        def.id = this.getId();
        def.type = this.getType();
        def.entityId = this._entityId;

        return def;
    };

    return Archetype;

});