Views and Layouts

As discussed in the Application Project article, an application built with the DevExtreme SPA framework is a single-page application. While such an application has only one web page, it can comprise several application screens defined as named views. A view is defined by a piece of HTML markup that forms the view template. This view template can optionally have JavaScript code and associated style sheets used to customize the look and feel.

Following the MVVM pattern, the view's markup template and style sheets serve as a View. The JavaScript function that is associated with the view prepares the ViewModel and performs the additional actions necessary to set up the view. These actions include interaction with the Model (a JavaScript object providing data, e.g. from a web server) and post-processing of the rendered view. The following diagram demonstrates this.

Application Structure

As you can see, a view's markup template is combined with other HTML elements defined within a layout's markup, which results in the rendering of the final view. You will learn how to define views and how to use custom or predefined layouts below.

Define a View

A view has a unique name that serves as an identifier. The view name is encoded into the fragment identifier of the application URL. The framework uses this name to find the view's HTML markup and the JavaScript function that returns the view's ViewModel.

To implement a view's HTML markup, add a div element and include the required markup in it. Set the div element's data-options attribute to dxView, and specify the required view markup options.

HTML
<div data-options="dxView: { name: 'home', title: 'Home' }">
    <h1>'Welcome!'</h1>
</div>

The view's markup may have bindings to the fields of the view's ViewModel. Implement the ViewModel as an object returned by a JavaScript function. This function must have the view's name and must be declared within the application's namespace.

View and Layout Merging

The ViewModel may get the required data from the view's Model - a JavaScript object in a general case. However, there may be scenarios when the ViewModel prepares data by itself.

Within the function that returns a ViewModel, you can use the information that is passed when navigating to the view. This information is accessible using the following parameters of the function.

  • Navigation parameters
    When navigating to a view, extra navigation parameters can be specified in addition to the name of the target view. These parameters conform to the application's routing format. You can access these navigation parameters as the fields of the object passed as the first parameter of the function that returns the ViewModel of the target view. To see an example, refer to the Pass a Parameter to a View step of the Your First Application tutorial.

  • View info
    The second parameter passed as the function's parameter represents an object that specifies the information that is gathered on the view by the time the function is called. The following fields of this object are accessible: key, viewName, uri, routeData, canBack and previousViewInfo.

NOTE
As you can see, binding to the ViewModel is organized using the Knockout framework. Generally, the ko.applyBindings() method should be called to activate Knockout. However, this method is called in DevExtreme applications internally. So you don't have to call this method in your code. At the same time, don't forget about this method, because when you insert a markup with the data-bind syntax dynamically, you will have to call the ko.applyBindings() method manually to initialize bindings.

Define Layouts

Normally, there is a commonality between application screens. In the following image, a toolbar and navigation bar are located on each screen.

View Merged into Layout

The framework allows you to organize some structure for each screen. This structure is called layout. It is defined once by a markup declared as a dxLayout markup component. This markup includes so-called placeholders for varying content. In the image above, the list on the first screen is changed to another list on the second screen and to a set of fields on the third screen. In addition, the title and a set of buttons on the toolbar are changed from screen to screen. The changing content is defined within the dxView markup component. When navigating to a view, the markup of the corresponding dxView template is merged with the markup of the required dxLayout component. The resulting markup is then rendered as a page.

View Merged into Layout

To define a layout, add a div element and include the required markup in it. Set the div element's data-options attribute to dxLayout, and specify the required layout markup options.

HTML
<div data-options="dxLayout: { name: 'myLayout'}">
</div>

To add a placeholder to a layout, add a div element, set the data-options attribute to dxContentPlaceholder and specify the required placeholder markup options.

HTML
<div data-options="dxLayout: { name: 'myLayout'}">
    <div data-options="dxContentPlaceholder: {name: 'content'}" ></div>
</div>

In the following image, you can see that a layout may include static content. This content is not changed from view to view. However, the content in placeholders is changing. When an application navigates to a view, the view's content is merged with the content of the layout content placeholders.

Content Placeholders

Since there can be several placeholders in a layout, their content will be shown sooner or later depending on the difficulty of the inner elements. So to show the entire changing content at once, wrap all the content placeholders by a div element and apply the data-options attribute set to dxTransition.

HTML
<div data-options="dxLayout: { name: 'myLayout'}>
    <div data-options="dxTransition: { name: 'main', animation: 'slide' }">
        <div data-options="dxContentPlaceholder : { name: 'header' } " ></div>
        <div data-options="dxContentPlaceholder: {name: 'content' }"></div>
        <div data-options="dxContentPlaceholder : { name: 'footer' } " ></div>
    </div>
</div>

Note that a transition element unites changing content. The markup outside this element is static.

Transition Element

Use the dxTransition component's animation configuration option to set the animation that will be used when the content that is rendered to the placeholders included to the dxTransition element is changed.

To set a specific transition effect for a specific content placeholder, exclude this placeholder from the dxTransition element and specify the animation option.

HTML
<div data-options="dxLayout: { name: 'myLayout'}>
    <div data-options="dxContentPlaceholder: {name: 'content', animation:'slide'}"></div>
</div>

In addition to an HTML markup, a layout is accompanied by CSS style sheets and is managed by a JavaScript controller. Generally, there is a base DefaultLayoutController that manages the process of showing views, navigation and transitions between views. To bind this controller with your layout markup, create an instance of this controller passing an object with the specified name field as a constructor parameter. Then, add this controller to the application's layout set defining a navigation context for this controller. Here is an example.

JavaScript
window.AppNamespace = {};
$(function () {
AppNamespace.myController = new DevExpress.framework.html.DefaultLayoutController({ name: "myLayout" })     
    AppNamespace.app = new DevExpress.framework.html.HtmlApplication({
        namespace: AppNamespace,
        layoutSet: [
            { platform: 'ios', phone: true, root: false, controller: AppNamespace.myController }
        ],
        //...
    });
    AppNamespace.app.router.register(":view/:name", { view: "home", name: '' });
    AppNamespace.app.navigate();
});

You can inherit from the DefaultLayoutController to override the basic functionality, if required. In this instance, you can bind a layout template within your controller. To take into account the custom controller, register its instance within the layoutSet list.

JavaScript
myController = DevExpress.framework.html.DefaultLayoutController.inherit({
    //your implementation here
});
AppNamespace.app = new DevExpress.framework.html.HtmlApplication({
    namespace: AppNamespace,
    layoutSet: [
        { platform: 'ios', phone: true, root: false, controller: new myController() }
    ],
    //...
});
AppNamespace.app.router.register(":view/:name", { view: "home", name: '' });
AppNamespace.app.navigate();

As a rule, you will not have to define layouts for your views. The framework comes with predefined layout sets. When a view is displayed, an appropriate layout controller from the application's layout set is used to render a layout markup for this view. To learn more about predefined layout sets, refer to the Built-in Layouts article.

JavaScript
$(function() {
    app = new DevExpress.framework.html.HtmlApplication({
        layoutSet: DevExpress.framework.html.layoutSets['navbar'],
        //...
    });
});

Insert View into Layout

When defining a view, specify the layout placeholder to which the view's markup will be rendered. To do this, wrap the required markup of the view by a div element, denote this element as the dxContent component and pass the name of the required placeholder as the targetPlaceholder option of this component.

HTML
<div data-options="dxLayout: { name: 'myLayout'}">
    <div data-options="dxContentPlaceholder: {name: 'content'}"></div>
</div>

<div data-options="dxView: { name: 'home', title: 'Home' }">
    <div data-options="dxContent: {  targetPlaceholder: 'content'}">
        <h1 data-bind="text: message"></h1>
    </div>
</div>

When you require different parts of a view to be displayed in different placeholders, wrap each part by the dxContent div and specify the required placeholder for it.

HTML
<div data-options="dxLayout: { name: 'myLayout'}">
    <div data-options="dxContentPlaceholder: {name: 'content1'}"></div>
    <div data-options="dxContentPlaceholder: {name: 'content2'}"></div>
</div>

<div data-options="dxView: { name: 'home', title: 'Home' }">
    <div data-options="dxContent: {  targetPlaceholder: 'content1'}">
    </div>
    <div data-options="dxContent: {  targetPlaceholder: 'content2'}">
    </div>
</div>
NOTE
If you wrap a view's content by a dxContent element, only the markup inside of the dxContent element(s) will be rendered to the resulting view. Read the View Life Cycle topic below for details.

The following image illustrates how the content of a dxView markup component is merged to a placeholder of the dxLayout markup component to prepare a final markup for the view.

View and Layout Merging

In some cases, you may be required to add a placeholder to a dxView component and define the content for this placeholder within a dxLayout component. The resulting view markup will be generated in the same manner - by merging the dxView and dxLayout markups.

View and Layout Merging

For instance, the "Navbar" and "Slideout" predefined layouts include the "dxContent: { targetPlaceholder: 'view-footer')" component in the "iOS" version. To render the markup of this component, the view that uses one of these layouts must include the "dxContentPlaceholder: { name: 'view-footer')" component in its markup.

Defer View Content Rendering

View rendering may take significant time. For instance, there may be a delay while waiting for data from a server or the view content may be so "heavy" that its rendering takes a lot of time. In this instance, an end-user should be notified that view content is being loaded so that the view does not look as broken. To indicate a loading state of a view, use the dxDeferRendering widget. Wrap the view content that will be shown with a delay by the widget's element.

HTML
<div data-options="dxView : { name: 'Products', title: 'Products' } " >
    <div  data-options="dxContent : { targetPlaceholder: 'content' } " data-bind="dxDeferRendering: { showLoadIndicator: true, renderWhen: isReady }" >
    </div>
</div>
JavaScript
MyApp.Products = function(params, viewInfo) {
    var isReady = $.Deferred();
    return {
        isReady: isReady.promise(),
        viewShown: function() {
          db.Products.load().done(function() {
              isReady.resolve();
           });
        }
    };   
};

The content enclosed into the dxDeferRendering widget is shown when the jQuery.Promise object assigned to the widget's renderWhen option is resolved. While waiting for the moment when the deferred content is allowed to be rendered, you can show a loading indicator. For this purpose, set the widget's showLoadIndicator option to true.

To specify the animation to be used when showing the deferred content enclosed to the dxDeferRendering widget, use the widget's animation option.

If your view is "heavy" enough, it may take a lot of time to display the whole view at once. So, you can divide the view into several blocks each enclosed into a separate dxDeferRendering widget. If you do not specify the renderWhen option of these widgets, the content of each dxDeferRendering widget will be rendered one after another from top to bottom. This will provide a quicker response to a user.

For details on the dxDeferRendering widget, refer to the dxDeferRendering topic.

Add a Partial View

You can display a view inside another view to reuse a markup (similar to partial rendering in ASP.NET MVC or ASP.NET user controls). To do so, create an empty div element inside a view's markup. To declare this element as the place where a specified view will be rendered, set the element's data-options attribute to dxViewPlaceholder and pass the name of the view to be rendered.

HTML
<div data-options="dxView: { name: 'header' }">
    <h1 data-bind="text: message"></h1>
</div>
<div data-options="dxView: { name: 'home' }">
    <div data-options="dxContent: {  targetPlaceholder: 'content' }">
        <div data-options="dxViewPlaceholder: { viewName: 'header' }"></div>
    </div>
</div>
NOTE
While a view (a main view) is rendered to a content placeholder in a layout markup, a partial view is rendered to a specified placeholder in a main view markup. So, make sure you do not use the dxContent markup component within partial views.

The partial view can be bound to its own ViewModel by using the "with" binding. This ViewModel can be the object assigned to the field of the parent view's ViewModel. Here is an example:

HTML
<div data-options="dxView: { name: 'credentials' }">
    <p data-bind="with: person">
        Name: <span data-bind="text: name"> </span>,
        Surname: <span data-bind="text: surname"> </span>
    </p>
</div>
<div data-options="dxView: { name: 'home' }">
    <div data-options="dxContent: {  targetPlaceholder: 'content' }">
        <div data-options="dxViewPlaceholder: { viewName: 'credentials' }"></div>
    </div>
</div>
JavaScript
MyApp.home = function (params) {
    var viewModel = {
        title: ko.observable('Home'),
        person: {
            name: params.name,
            surname: params.surname
        }
    };
    return viewModel;
};

Context Specific Markup

You can define view and layout HTML templates for specific contexts. When running an application, the HTML template that is most appropriate for the current context will be used to display a view. Below, you will learn how to define templates specific for different contexts.

NOTE
Be sure to provide view templates that are not simultaneously functional in a specific context. For instance, both a template for the iOS platform and a template for the iPhone will work when an application runs on an iPhone device. When several templates may be appropriate for a view, an exception will be raised. To avoid such scenarios, define a single common template or multiple templates that are as specific as possible.

Device Specific Markup

You can define multiple views/layouts with the same name that are targeted for different devices. To set a target device for a view/layout, use the fields of the device object as markup options of the dxView/dxLayout components.

HTML
<div data-options="dxView: { name: 'home', platform: 'ios', phone: true }">
    This is a view for an iPhone.
</div>

<div data-options="dxView: { name: 'home', platform: 'ios', tablet: true }">
    This is a view for an iPad.
</div>

As you can see, you can specify the target platform as well as the device type.

A DevExtreme application, when running, retrieves information about the device from the browser. Thus, the application will display the views and layouts that are most appropriate for the used device, and will then apply the style sheets that correspond to this device.

See a step-by-step example in the Define Device-Specific View Markup tutorial.

Orientation Specific Markup

You can define view templates that are specific to the 'portrait' and 'landscape' device orientations. To set a target device orientation for a view, use the orientation configuration option of the corresponding dxView markup component. In the following example, the 'home' view will have data displayed using the dxList widget when the device on which the application is currently displayed has a 'portrait' orientation. When changing the device orientation to 'landscape', the 'home' view will be rerendered. In the newly applied HTML template, data will be displayed using the dxTileView widget. When rotating the device back to the 'portrait' orientation, the view will be rerendered and will display data using the dxList widget again.

HTML
<div data-options="dxView : { name: 'home', title: 'Home', orientation: 'portrait' } " >
    <div class="home-view"  data-options="dxContent : { targetPlaceholder: 'content' } " >
        <div data-bind="dxList: { dataSource: dataSource }">
            <div data-options="dxTemplate : { name: 'item' } " >
                <div class="product-image-box">
                    <img data-bind="attr: { src: Image, alt: Name }" />
                </div>
                <div>
                    <div data-bind="text: Name"></div>
                    <div><strong data-bind="text: Globalize.format(Price, 'c2')"></strong></div>
                </div>
            </div>
        </div>
    </div>
</div>

<div data-options="dxView : { name: 'home', title: 'Home', orientation: 'landscape' } " >
    <div class="home-view"  data-options="dxContent : { targetPlaceholder: 'content' } " >
        <div data-bind="dxTileView: { dataSource: dataSource, height: '100%', baseItemHeight: 140, baseItemWidth: 140 }">
            <div data-options="dxTemplate : { name: 'item' } " class="gallery-item">
                <img data-bind="attr: { src: Image, alt: Name }" />
                <div data-bind="text: Name"></div>
                <div><strong data-bind="text: Globalize.format(Price, 'c2')"></strong></div>
            </div>
        </div>
    </div>
</div>

Watch Video

Custom Context Specific Markup

You can introduce a custom context for a view template by specifying a custom option within the configuration object of the corresponding dxView markup component. In the following example, the 'home' view has two HTML templates - for day and night.

HTML
<div data-options="dxView : { name: 'home', title: 'Home', timeOfDay: 'day' } " >
    <div data-options="dxContent : { targetPlaceholder: 'content' } " >
        <p>It's time to work</p>
    </div>
</div>

<div data-options="dxView : { name: 'home', title: 'Home', timeOfDay: 'night' } " >
    <div data-options="dxContent : { targetPlaceholder: 'content' } " >
        <p>It's time to sleep</p>
    </div>
</div>

To notify the application that the timeofDay context has changed, access the application's templateContext object and set the timeofDay option for it using the option(optionName, optionValue) method.

JavaScript
var templateContext = Application.app.templateContext();
function timeOfDayChangedHandler(currentTimeOfDay) {
    templateContext.option("timeOfDay", currentTimeOfDay);
}

Context Specific View Model

The DevExtreme SPA framework allows you to define a view markup specifically for the current context (for a particular platform, device orientation or any custom context). You can learn how to do this in the Context Specific Markup topic. At the same time, you may need to have ViewModel fields specific to the current context too. In this instance, use the view's viewShown and viewHidden events to subscribe to and unsubscribe from tracking a context change.

The following example demonstrates how to change a view title when device orientation changes.

JavaScript
function onOrientationChanged(e) { viewModel.title(e.orientation); }
var viewModel = { 
    title: ko.observable(DevExpress.devices.orientation()), 
    viewShown: function() { 
        DevExpress.devices.on("orientationChanged", onOrientationChanged); 
    }, 
    viewHidden: function() { 
        DevExpress.devices.off("orientationChanged", onOrientationChanged);
    } 
};

Add Commands to Views

A view may include a functionality for performing operations. Suppose you want a view to contain "Back" and "Add" buttons. In an application designed for the iPhone, the "Back" button must be located on the left side of the title bar and the "Add" button must be located on the right side of the title bar. If you want to make an application for an Android phone, you will have to display the "Add" button on the bottom navbar, and not display the "Back" button at all, since the phone has a "Back" button built into the hardware. When implementing an application that will be run on both the iPhone and an Android phone, you will not only have to define two different layouts, but also create and manage different widgets for these platforms. To make things simpler, we offer you the ability to define a single view with two commands, so that you don't have to manually manage different widgets. We provide buttons created for commands that will work properly on both iPhone and Android devices; these buttons will also deliver a native user experience.

A command is an abstract action associated with a view. Commands help you produce truly cross-platform applications with a native look and feel.

Commands are declared in a view markup within a root element. To add a command, use a Knockout binding syntax. Declare the command by using the data-bind attribute and pass the required markup options. These options include: the command identifier, the handler to be performed when executing the command, as well as a title, an icon, and enabled and visible states.

HTML
<div data-options="dxView: { name: 'home', title: 'Home' }">
    <div data-bind="dxCommand: { id: 'myCommand', onExecute: '#product-details', title: 'Add' } "></div>
</div>

Command markup options can be bound to a ViewModel's fields. Here is an example.

HTML
<div data-options="dxView: { name: 'home', title: 'Home' }">
    <div data-bind="dxCommand: { id: 'myCommand', onExecute: add, title: 'Add' } "></div>
</div>

To function properly, the code above must be accompanied by the ViewModel object that exposes the "add" field. This field can be a function that is called when you are executing the Add command or a string/object representing the URL to navigate to. To learn how to define a URL using a string or an object, refer to the Navigate to a View section.

In some scenarios, it is not appropriate to add commands to a view using the view's markup. For instance, you may need to add the same commands to several views, or to populate a command collection dynamically (within the onViewShown event handler), etc. For this purpose, the DevExtreme SPA framework allows you to define a command collection within a ViewModel object.

JavaScript
var viewModel = {
    commands: [ an array of commands can be here ]
};

The objects that represent commands in the commands array must have the same structure as the configuration objects of the dxCommand markup components.

You can see an example of defining the commands array within a ViewModel object in the Add Global Navigation Commands to a View tutorial.

To display commands, the layout in which a view is displayed must include command containers. These are the elements in the layout markup that are marked by the data-options attribute set to dxCommandContainer. The following code demonstrates a command container that displays commands by toolbar items.

HTML
<div class="layout-header">
    <div data-bind="dxToolbar: { items: [ { text: title, align: 'center' } ] }" 
        data-options="dxCommandContainer : { id: 'my-container' }">
    </div>
</div>

As there can be several command containers in a layout, and the layout can have several versions - each for a certain platform/type of a device, you should declare that a particular command must be displayed in a particular command container. For this purpose, use the application's command mapping.

JavaScript
new DevExpress.framework.HtmlApplication({
    commandMapping: {
        'my-container': {
            defaults: {
                'showIcon':false, 
                'location':'before'
            },
            commands: [
                {
                    id: 'myCommand',
                    location: 'after' // container defaults can be overriden
                }
            ]
        }
    }
});

When using predefined layouts for views, put your commands to the command containers that are available in these layouts. To learn which command containers are available in these layouts, refer to the Predefined Layouts topic. An application loads default mapping of the "create", "edit", "save", "delete", "cancel" and "back" commands to the command containers of the predefined layouts, and then extends it by your custom command mapping declared within the application's configuration object. If you use the specified identifiers for your commands, these commands are automatically mapped to the command containers of the predefined layouts. It is only required that you define a mapping for your custom commands. To learn what commands are mapped to the built-in layouts by default, refer to the Default Command Mapping topic.

Depending on the command container chosen for a command in a layout and the device the application is running on, different widgets will be used to display commands. You can specify widget configuration settings directly within the dxCommand component's configuration object.

HTML
<div data-bind="dxCommand: { id: 'myCommand', onExecute: '#product-details', title: 'Add', hint: 'Add a product' } "></div>

In the code above, the specified hint option will be applied if the widget that will display the command has the hint option in its configuration.

View Life Cycle

The replacement of a view with another view is initiated by invoking the navigate method of the HtmlApplication object. When the application navigates to a view, the previous view is hidden or disposed. When it is hidden, this view can be restored from the cache quickly to be displayed again. When it is disposed, a new life cycle is initiated when the application navigates to this view repeatedly. All of the view life cycle steps are detailed below.

  1. Get View Info
  2. Create a View Model
  3. Render the View
  4. Show the View
  5. Hide the View
  6. Display the View Repeatedly
  7. Dispose the View

1 - Get View Info

Step 1

When a view's display process begins, the only thing we know about the view is its name. It is the view name that is specified in the URI passed as the navigate function's parameter or the default view name specified in the routing rule. To get more information about the view, the application's view cache is used. Information on all views that are contained in the current navigation history is stored within the cache. However, there can be no information on a view in the cache, because the view was removed during the application flow, or the view has not been displayed before or the cache is disabled. In this instance, the information on the view is gathered from scratch and added to the cache, so that the next time everything that is needed to display this view is contained in the cache.

viewInfo is an object that collects information on a view gathered during the whole view display process. At this step, the fields of this object provide the following information on the view.

  • viewName
    A string specifying the name of the displayed view.

  • routeData
    An object representing route parameters for the displayed view.

  • uri
    The URI to which the application is currently navigating.

  • viewTemplateInfo
    An object that provides the specified values of the dxView component options.

  • layoutController
    The controller that will be used to display the view within the layout markup. This controller, like all controllers that are registered in the application, is initialized beforehand.

The following events of the HTMLApplication object can be handled to change the flow of the view display at this step.

  • navigating
    This event fires at the very beginning - before you search the view in the cache. Handle this event to cancel the display of the view, or to redirect to another view. For this purpose, use the cancel and uri fields of the object passed as a parameter.

  • resolveLayoutController
    This event fires before an appropriate layout controller from the application's layout set is found, based on the current navigation context. Handle this event to set a custom layout controller for the displayed view. This layout controller will use the required layout template for the view.

2 - Create a View Model

Step 2

To get the View Model object, a function with the same name as the view is searched for in the application's namespace, and, if found, the function is called. The object returned by this function is the view's ViewModel.

The following events of the HTMLApplication object can be handled to change the flow of the view display at this step.

  • beforeViewSetup
    This event fires before creating the ViewModel object. You can set a custom ViewModel object to be used for the view. To do this, add the model field to the viewInfo object. This object can be accessed using the viewInfo field of the object passed as a parameter.

  • afterViewSetup
    This event fires after the ViewModel object is created for the view. At this time, you can modify the created ViewModel object. It is available to you as the model field of the viewInfo object exposed by the parameter object.

3 - Render the View

Step 3

When showing a view for the first time or when information on it has been removed from the cache, the viewInfo object does not contain the renderResult field. At this step, the view is rendered and the result of the rendering is assigned to this field.

To be shown within the layout, the content of the view's dxContent elements is merged with the corresponding dxContentPlaceholder elements of the layout. The merged result is added to the corresponding dxTransition element of the layout as an additional view markup in an inactive state.

View Rendering

NOTE
Only the markup that is added to the dxContent elements will be rendered to the resulting view.

The following events of the HTMLApplication object can be handled to change the flow of the view display at this step.

  • viewRendered
    This event fires after markup was rendered for the view. This markup can be accessed using the markup field of the renderResult object that is exposed by the viewInfo object passed as the event handler's parameter.
NOTE
The rendering process may take a lot of time in some views. In this instance, you can defer the rendering of some view elements and provide a quick request to an end-user. For this purpose, use the dxDeferRendering widget within the view. The content enclosed into this widget will be rendered and shown with specified animation at a specified moment. While waiting for this moment, the view will be shown with a loading indicator or a custom loading state indication. For details on how to use the dxDeferRendering widget for views, refer to the Defer View Content Rendering topic.

4 - Show the View

Step 4

To show the view, the inactive markup corresponding to this view is made active while other markup elements, which correspond to the previously shown view, are made inactive.

Show View

NOTE
You can access the active view using the $('.dx-active-view .my-selector') selector.

Handle the following event at this step.

  • viewShowing
    This event is raised before showing the view.

  • viewShown
    This event fires each time after a view is displayed. Handle this event to refresh data in the view each time the view is shown. Access the view's ViewModel using the model field of the object passed as the viewInfo parameter.

5- Hide the View

If the navigation to another view implies conserving the current view in the navigation history, the view markup becomes inactive. Information on the view is stored in the cache.

Handle the following event at this step.

  • viewHidden
    This event fires each time after a view is hidden. Access the viewInfo object using the viewInfo field of the object passed as a parameter.

6 - Display the View Repeatedly

The next time the application navigates to the view, the view is ready to be displayed if information on this view is stored in the cache. If the previous view was displayed by the same layout controller, there is an "inactive" markup of the current view in the dxTransition element of the layout. So, the view is made active and the previous active content is made inactive.

Show View

If the layout controller of the previous view is not the controller of the displayed view, the previous controller is deactivated first. This means that the layout markup provided by this controller is removed from the view port element of the application page. The controller of the view that must be displayed is then activated. Therefore, the layout markup provided by this controller is inserted to the view port element of the application page.

View-related events are raised in the following order.

7 - Dispose the View

The following events are raised when the current view is not displayed and information on this view has already been removed from the cache.

  • viewDisposing
    This event is raised before disposing of the view.

  • viewDisposed
    This event is raised after disposing of the view.

Handle View Events

The HtmlApplication object exposes the events that are raised for each view displayed in the application. You can handle these events to perform certain actions for all the views in the application. At the same time, you may need to handle a particular event for a certain view only. In such a case, add a field with the event's name to the view's ViewModel and assign the required function to it. The following is the list of the events that can be handled in this manner.

For instance, you can handle the viewShowing event to get the required data for the view. In the following example, the viewShown event is handled to set a focus to a particular numberbox on the view.

HTML
<div data-options="dxView : { name: 'home' }">
    <div class="dx-fieldset">            
        <div class="dx-field">
            <div class="dx-field-label">Bill Total:</div>                
            <div id="billTotalInput" class="dx-field-value" data-bind="dxNumberBox: { value: billTotal, placeholder: 'Type here...', valueChangeEvent: 'keyup', min: 0 }"></div>
        </div>
    </div>
</div>
JavaScript
MyApp.home = function(params) {
    var billTotal = ko.observable(),
    //...
    function viewShown() {
        $("#billTotalInput").dxNumberBox("instance").focus();
    }
    return {
        billTotal: billTotal,
        viewShown: viewShown,
        //...
    };
};

See a step-by-step example in the Handle View Events tutorial.