Creating the films container

The next step is creating the Films screen that we presented at the beginning of this chapter. It consists of a toolbar with a button (Add), the Films grid, and two associated grids (Categories and Actors). We are going to create this View in the Films.js file, as follows:

Ext.define('Packt.view.film.Films', {
    extend: 'Ext.panel.Panel',
    xtype: 'films',

    requires: [
        'Packt.view.base.TopToolBar',
        'Packt.view.film.FilmsGrid',
        'Packt.view.film.FilmActorsGrid',
        'Packt.view.film.FilmCategoriesGrid',
        'Packt.view.film.FilmsModel',
        'Packt.view.film.FilmsController'
    ],

    controller: 'films', //#1
    viewModel: {
        type: 'films'    //#2
    },

    session: true,       //#3

    layout: {
        type: 'vbox',
        align: 'stretch'
    },

    items: [{
        xtype: 'films-grid',  //#4
        flex: 1
    },{
        xtype: 'container',
        split: true,
        layout: {
            type: 'hbox',
            align: 'stretch'
        },
        height: 150,
        items: [{
            xtype: 'film-categories', //#5
            flex: 1
        },{
            xtype: 'film-actors',    //#6
            flex: 2
        }]
    }],

    dockedItems: [{
        xtype: 'top-tool-bar'    //#7
    }]
});

In this class, we declared a ViewController (#1) and also the ViewModel (#2). The ViewModel was already created, so we need to create the ViewController.

Next, we have session (#3). If provided, this creates a new session instance for this component. As this class is a container for other classes, the session will then be inherited by all child components. We will dive into the session when we work in the ViewController.

In line #4, we have the FilmsGrid class we created. And in lines #5 and #6 ,we have the categories and actors grid that we will use to display the many-to-many association.

We also have TopToolBar declared in line #7. This toolbar was created separately, so we can reuse it, as follows:

Ext.define('Packt.view.base.TopToolBar', {
    extend: 'Ext.toolbar.Toolbar',
    xtype: 'top-tool-bar',

    requires: [
        'Packt.util.Glyphs'
    ],

    dock: 'top',
    items: [
        {
            xtype: 'button',
            text: 'Add',
            itemId: 'add',
            glyph: Packt.util.Glyphs.getGlyph('add'),
            listeners: {
                click: 'onAdd'
            }
        }
    ]
});

We cannot forget to update the menu table to reflect the films xtype:

UPDATE `sakila`.`menu` SET `className`='films' WHERE `id`='11';

We will be adding more buttons to this toolbar in the next chapter.

Handling many-to-many associations

The film and category tables are associated by a many-to-many relationship. When this happens, a matrix table is created with two columns to hold the IDs of a pair of related entities. There is a matrix table representing the many-to-many relationship between the film and category tables, called film_category and a table called film_actor representing the many-to-many relationship between film and actor.

To represent a many-to-many relationship in Ext JS, we will add the following code to the Film Model:

manyToMany: {
    FilmCategories: {         //#1
        type: 'Category',     //#2
        role: 'categories',   //#3
        field: 'category_id', //#4
        right: {
            field: 'film_id', //#5
            role: 'films'     //#6
        }
    },
    FilmActors: {
        type: 'Actor',
        role: 'actors',
        field: 'actor_id',
        right: {
            field: 'film_id',
            role: 'films'
        }
    }
}

For each many-to-many relationship, we need to define a name (#1). The name must be unique within the schema. We also need to define a type (#2). The type is the name of the model of the association—we can use entityName to define the associated Model. We can also define role (#3), which will be the name of the method generated to retrieve the associated data. We also need to specify the foreign key (#4) used to identify the association. As the many-to-many relationship is created between two tables, we can also specify the information that links this Model to the matrix table, which is the field (foreign key—#5) and also the role of the association in the Category and Actor models (#6).

In the Category Model, we will also declare the many-to-many association:

manyToMany: {
    CategoryFilms: {
        type: 'Film',
        role: 'films',
        field: 'film_id',
        right: {
            field: 'category_id',
            role: 'categories'
        }
    }
}

And we will do this inside the Actor Model as well:

manyToMany: {
    ActorFilms: {
        type: 'Film',
        role: 'films',
        field: 'film_id',
        right: {
            field: 'actor_id',
            role: 'actors'
        }
    }
}

Loading nested JSON from the server

In the server-side code, we need to retrieve the film information and its categories and actors as well. The JSON that the server will return to Ext JS will have the following format:

{
   "success":true,
   "data":[
      {
         "film_id":"1",
         "title":"ACADEMY DINOSAUR",
         "description":"A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies",
         "release_year":"2006",
         "language_id":"1",
         "original_language_id":null,
         "rental_duration":"6",
         "rental_rate":"0.99",
         "length":"86",
         "replacement_cost":"20.99",
         "rating":"PG",
         "special_features":"Deleted Scenes,Behind the Scenes",
         "last_update":"2006-02-15 05:03:42",
         "categories":[
            {
               "category_id":"6",
               "name":"Documentary",
               "last_update":"2006-02-15 04:46:27"
            }
         ],
         "actors":[
            {
               "actor_id":"1",
               "first_name":"PENELOPE",
               "last_name":"GUINESS",
               "last_update":"2006-02-15 04:34:33"
            },
            {
               "actor_id":"10",
               "first_name":"CHRISTIAN",
               "last_name":"GABLE",
               "last_update":"2006-02-15 04:34:33"
            }
         ]
      }
   ],
   "total":"1000"
}

Note

The server-side code is included within the source code of this book.

If we inspect a Film Model instance of the films Store, we will see that a function/method is created for each of the associations, as follows:

Loading nested JSON from the server

Note

When accessing model.actors() or model.categories(), the methods will return a Store for each association and not an array of the Actor or Category Model.

Changing the ViewModel – chained stores

Ext JS will understand the association and will be able to create the methods and associated stores, but we need to add the stores to the session as well by adding the actors and categories Store in the same ViewModel, as follows:

categories: {
    source: 'staticData.Categories',
    autoLoad: true,
    session: true
},
actors: {
    source: 'staticData.Actors',
    autoLoad: true,
    session: true
}

Note the highlighted code. The stores we are creating use existing stores (which we created in the preceding chapter, and which are available in the global scope of the application through their storeId) through a source configuration. This capability was also introduced in Ext JS 5, and it is called a chained store (Ext.data.ChainedStore). A chained store is a store that is a view of an existing store. The data comes from the source; however, this view of the store can be sorted and filtered independently without having any impact on the source store. This is very useful when we want to have two different stores with synchronized data, but independent instances.

Film-Actor – handling many-to-many associations

Now that we have the many-to-many association in place, we can create the FilmActorsGrid class. This class will have the following content:

Ext.define('Packt.view.film.FilmActorsGrid', {
    extend: 'Ext.grid.Panel',
    xtype: 'film-actors',

    requires: [
        'Packt.util.Glyphs'
    ],

    bind : '{filmsGrid.selection.actors}', //#1
    border: true,

    title: 'Film Actors',
    glyph: Packt.util.Glyphs.getGlyph('actor'),

    columns: [
        {
            text: 'Actor Id',
            width: 80,
            dataIndex: 'actor_id'
        },
        {
            xtype: 'templatecolumn',
            text: 'Actor Name',
            flex: 1,
            tpl: '{first_name} {last_name}' //#2
        }
    ]
});

This grid contains a column we have not used so far, which is the Template Column. When using this column, you can create a template to display more than one field (#2) instead of using a renderer function to do so.

The preceding code presents how to display associated data in a detail grid. When we select a film from the FilmsGrid, the Actors grid will automatically display the associated data by binding the actors (role of the association) with the Actors grid (#1).

Film-Category – handling many-to-many associations

We will use the same approach used for the Film-Actor many-to-many associations for the Film-Category many-to-many associations. We will create a class named FilmCategoriesGrid. This class will have the following content:

Ext.define('Packt.view.film.FilmCategoriesGrid', {
    extend: 'Ext.grid.Panel',
    xtype: 'film-categories',

    requires: [
        'Packt.util.Glyphs'
    ],

    bind : '{filmsGrid.selection.categories}', //#1
    border: true,

    title: 'Film Categories',
    glyph: Packt.util.Glyphs.getGlyph('category'),

    columns: [
        {
            text: 'Category Id',
            width: 100,
            dataIndex: 'category_id'
        },
        {
            text: 'Category Name',
            flex: 1,
            dataIndex: 'name'
        }
    ]
});

We will also bind the Store of this grid to the data loaded from the association (#1).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset