I am the best message

Refer to the Messages.js file in the following code:

// app/view/messages/Messages.js
Ext.define('Postcard.view.messages.Messages', {
    extend: 'Ext.Panel',
    xtype: 'messages',
    controller: 'messages',
    viewModel: 'messages',
    autoScroll: true,
    session: true,
    bbar: [
        {
            xtype: 'combobox', displayField: 'name',
            idField: 'name',
            reference: 'tagPicker',
            queryMode: 'local', value: 'Inbox',
            bind: { store: '{tags}' }
        },
        {
            text: 'Set Tag',
            itemId: 'setTag'
        },
        '->',
        {
            text: 'Reply',
            itemId: 'reply',
            reference: 'replyButton'
        }
    ],
    items: [{
        xtype: 'dataview',
        bind: '{messages}',
        flex: 1,
        cls: 'message-view',
        tpl: new Ext.XTemplate('<tpl for=".">',
            '<div class="message">',
                '<div class="date">{date:date("H:m")}</div>',
                '<div class="details">',
                    '<tpl if="xindex == 1">',
                    '<div class="header">{people} - {subject}</div>',
                    '</tpl>',
                    '<div class="body">{body}</div>',
                '</div>',
            '</div>',
        '</tpl>'),
        itemSelector: '.message'
    
});

In an ideal situation, the code should flow out of your team as the culmination of the design process. Any difficult classes or methods should have been part of a code spike. Your data layer would have been designed on top of your backend API. User interface has been described in wireframes, user stories provide routing, and so on.

This is what we're seeing now. As seasoned Ext JS developers, we know how to configure a combo box and a store. This book is not here to help with that. We're going to continue to focus on the design and the decisions that make your code simple.

Look at the previous class. The design of the messages view with its DataView nested inside a panel allows you to use a bbar; we knew about this before we even wrote a line of code. This is the crux of a good design. With developers who understand the technology they are working with, implementations become easy and predictable because it's all been thought about in advance.

Messages ViewModel

Refer to ViewModel in the following code:

// app/view/messages/MessagesModel.js
Ext.define('Postcode.view.messages.MessagesModel', {
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.messages',
    stores: {
        messages: {
            type: 'messages'
        },

        tags: {
            type: 'tags',
            session: true
        }
    }
});

See! With an up-front design, you can pass the documentation over to a developer and have them create the messages view model. There's little scope for error because the shape of the class has already been decided.

Messages ViewController

Having said that, there are times when the code is lengthy, so a breakdown of what's happening really helps as shown here:

// app/view/messages/MessagesController.js
Ext.define('Postcard.view.messages.MessagesController', {
    extend: 'Ext.app.ViewController',
    alias: 'controller.messages',

    listen: {
        component: {
            '#reply': {
                click: 'onReplyClick'
            },

            '#setTag': {
                click: 'onTagChange'
            }
        }
    },

    routes: {
        'thread/:id/messages': 'onShowThread',
        'thread/new': 'onNewThread'
    },

    onShowThread:function(id) {
        this.getViewModel().get('messages').load({
            params: {
                parentId: id
            },
            callback: function(records) {
                this.getView().show();
            },
            scope: this
        });
    },

    onNewThread: function() {
        this.getView().hide();
    },

    onReplyClick: function() {
        this.redirectTo(window.location.hash + '/new'),
    },

    onTagChange: function() {
        var tagPicker = this.lookupReference('tagPicker'),
            newTag = tagPicker.getValue(),
            viewModel = this.getViewModel(),
            threadParent = viewModel.get('messages').getAt(0);

        threadParent.set('tag', newTag);
        threadParent.save({
            callback: function() {
                this.getViewModel().get('tags').reload();
                this.fireEvent('tagadded'),
                this.fireEvent('threadschanged'),
            },
            scope: this
        });
    }
});

As usual, we have our event listeners. Let's look at the component ones; firstly the one that handles the reply button's click event as it's straightforward. It just redirects to a route that will take care of setting up the application to reply to a thread.

Next, there's the onTagChange method that handles a click on the "set tag" button. This will get the selected value from the tag combo box and set it as the tag for the first message in the thread. Then, it saves that message to the server.

Note the callback for this save request (it fires off two events that we've seen before). One (threadschanged) notifies the application that threads have changed in some way; in this case, it's a thread's tag that has changed, so a thread list may need to be refreshed. The other (tagadded) signifies that there may be a new tag and any interested classes should refresh their tag data accordingly.

The next two handlers are for routes, but there's something to note here. These routes have already been handled by the main view controller! This is a powerful feature; we can handle routes in multiple locations so that the classes that are interested in this route can do their own thing. This avoids us having to do all of the work in the main view controller, for example, the messages view controller can take care of loading the messages rather than doing so in the main view controller.

Compare using routes in this way to using events. They're very similar; we can redirect to a route, fire this redirect and forget about it, or else, where in the application a controller will handle this route. With routes, you get the added benefit of keeping state in the URL, thus enabling bookmark support. With events, you can send complex data in the event arguments. Both have their strengths.

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

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