Application Packaging Standard

Last updated 18-Mar-2019

Typical Structure of View File

This section contains step-by-step instructions on developing a view source based on the CP environment. The structure of a view in UX1 used in a single page application looks differently.

When developing an *.html or *.js file with the help of APS JS SDK, do the following operations.

  1. Include the APS JS runtime library:

    <script src="/aps/2/ui/runtime/client/aps/aps.js"> </script>
    
  2. Require the modules from the APS JS SDK, Dojo library, and other that the JavaScriptcode will need. For this purpose, in PCP/CCP v1, use the require([<list of required modules>], <callbackFunction>(...) {...}); function. The latest of the required modules must be “aps/ready!”. It activates the CP to start building the view screen. On completion of this initialization, the callback function (hereafter - main callback function) will be activated. The list of arguments in the main callback function must strictly correspond to the list of required modules, for example:

    require([
          "aps/ResourceStore",
          "dojo/when",
          "dijit/registry",
          "aps/parser",
          "aps/Message",
          “./displayError.js”,
          "aps/ready!"
          ], function(Store, when, registry, parser, Message, displayError) {
       // ...
    });
    

    View structure in UX1 looks a bit differently.

    Warning

    Declarative require is NOT recommended and not supported. For example, avoid a code similar to the following:

    <script type="dojo/require">at: "dojox/mvc/at"</script>
    

    Follow Inclusion Rules when adding custom JS modules to the require method.

  3. Place the active part (JS code) inside the main callback function.

  4. Define widgets using one of methods:

    Below is an example of defining and loading widgets:

    load(["aps/PageContainer", { id: "page" }, [
       ["aps/Grid", {
          id:                "srv_grid",
          store:             store,
           selectionMode:     "multiple",
          apsResourceViewId: "server-edit",
          columns:           [
             { field: "name", name: "Name", filter: { title: "Name" }, type: "resourceName" }
          // Other columns ...
    ]]]).then(function() {
       // Processing data...
       // ...
    });
    

    The load method is asynchronous. The callback function with data processing starts only after the widgets are loaded. Each widget is identified by its ID, specified in the declaration. For example, the grid widget in the example above is identified as registry.byId("srv_grid").

  5. Define processing of widgets inside the callback function. The following example illustrates processing of the Start button declared in grid definition:

    registry.byId("start").on("click", function() {
        var page = registry.byId("page");
        var grid = registry.byId("srv_grid");
        // ...
    });
    
  6. Define navigation to other views.

    To dynamically navigate to a view, call the aps.apsc.gotoView() method. To bind this function to a navigation control, a proper event handler is used. For example, the Cancel button inside the server-new view returns a user back to the list of servers, that is to the servers view, as defined below.

    aps.app.onCancel = function() {
       aps.apsc.gotoView("servers");
    };
    
  7. Add the store and model controls to widget definition and data processing as needed.

    • A store control provides access to one or more resources in the APS database. Typically, the store object will get all resources of the specified type that were created in the current subscription:

      vpsStore = new Store({
          apsType: "http://aps-standard.org/samples/basic/vps/1.0",
          target: "/aps/2/resources/"
      });
      

      The target in the above definition is the REST path to the APS resource list. To update the APS database, call the store put asynchronous operation. As illustrated below, the callback function() will be called on completion of the vpsStore.put(vps) operation, that is after the store updates the APS database:

      when(vpsStore.put(vps),
          function() {
             ...
          }
      );
      
    • A model control is needed in active forms interacting with a user. It initializes the bound wizards and then collects wizard values synchronously. The following steps illustrate how to use a model control when editing a VPS in the server-edit view. This view can be started from the list of servers displayed by the servers view.

      1. In the APP-META.xml file, inside the server-edit view definition, declare a variable, for example, vps, referring to the APS type used for processing VPSes:

        <view id="server.edit" label="Edit">
            <var name="vps" type-id="http://aps-standard.org/samples/basic/vps/1.0"/>
        </view>
        
      2. In the servers view, make the server name field clickable and configure the grid control to launch the view-edit control when a user clicks on a server name. The visual context object passed to the view will contain the clicked server JSON representation assigned to the vps variable.

      3. In the server-edit view, create a model control that must capture the VPS resource from the APS database. The model will represent the VPS (its model) as a JSON object for the JS code. For this purpose, assign the vps variable from the APS context to the new model:

        model = aps.context.vars.vps;
        
      4. Bind the model to widgets using the 2-way synchronization. The following code is an example of how to define widgets statically in JS and how to bind the serverName widget with the model.name property.

        var widgets = ["aps/PageContainer", {id: "page"}, [
          ["aps/FieldSet", {title: true}, [
              ["aps/TextBox", {
                  id: 'serverName',
                  label: _('Server Name'),
                  value: at('model', 'name'),
                  required: true
              }],
              ...
          ]]
        ]];
        

        Due to this code, when the serverName widget is created, its initial value will be assigned from the model.name property. After that, any changes in the widget will be assigned to model.name synchronously.

      5. When the Submit button is pressed, the model should be saved in the APS database to update the edited VPS. The best way to do it is using the store control.

        aps.app.onSubmit = function() {
            when(store.put(getPlainValue(model)),
                function(//...) {
                  // ...
                }
        }
        
  8. Define error processing. In some cases, you need to display error messages in the CP and in the log. Some of messages help you debug the code and thus are used temporarily. Some will remain in the production code. A typical example is considered below:

    • Create a JS module for error processing in a separate file. For example, the displayError.js file that uses the dijit/registry, aps/Messages, and aps/PageContainer modules can look as follows:

      define(["dijit/registry", "aps/Message", "aps/PageContainer"],
        function (registry, Message, PageContainer) {
            return function(err) {
                var errData = err.response ? JSON.parse(err.response.text) : {message: err};
                aps.apsc.cancelProcessing();
      
                var page = registry.byId("page");
                if(!page) {
                    page = new PageContainer({ id: "page" });
                    page.placeAt(document.body, "first");
                }
                var messages = page.get("messageList");
                /* Remove all current messages from the screen */
                messages.removeAll();
                /* And display the new message */
                messages.addChild(new Message({description: err + (errData.message ?
                        "<br />" + errData.message : ""), type: "error"}));
            };
        }
      );
      
    • Require the error module and use its function to process errors wherever you need:

      require([..., "./displayError.js", ...],
          function(..., displayError, ...) {
             ...
             when(store.put(vps),
                function() {
                   ...
                },
                function(err) { displayError(err) }
             );
          }
      );
      

Please search for more examples in the Integration Procedures section.