Data-driven design

In the same way that we designed our application by looking at the data layer first, we'll write the Ext JS model and store code first. Here's the model, which we'll build bit-by-bit to explain the thought process behind the code:

Ext.define('ArchitectureCms.model.Page', {
   extend: 'Ext.data.TreeModel',
fields: [
        { name: 'body' },
        { name: 'stub' },
        { name: 'text' },
        { name: 'published' }
    ]
});

Let's look back at our design for this class. We're defining the same fields we laid out there with the exception of the children field, which is a special case as we're using Ext.data.TreeModel.

Of course, this isn't enough to drive a real-world Ext JS model. This is where the design now differs from the implementation. Let's connect the model to the client's API:

Ext.define('ArchitectureCms.model.Page', {
    extend: 'Ext.data.TreeModel',
 
    fields: [
        { name: 'body' },
        { name: 'stub' },
        { name: 'text' },
        { name: 'published' }
    ]
});

Woah! The design is mostly language agnostic, but the implementation now shows off configuration options that are very Ext JS-specific. There are two ways of configuring a model. One way to configure is via its proxy and another is via its schema. The proxy configuration works just fine, but in larger applications, the schema can be shared between models and provides a central place to configure the base API URL and the path to fetch for a particular model.

Because of this, we're going to start off using schema even though we're only dealing with a single model in this application. Let's look at the various configuration options:

  • namespace: This is the segment of the model's class name that represents the namespace. This means that Ext JS can remove the namespace part of the full class name and be left with nothing but the model, which it can then use to automatically build URLs. In this case, we set the namespace as ArchitectureCms.model, which allows Ext JS to work out that the model name is just Page. We'll use this later.
  • urlPrefix: This is generally the hostname or the API endpoint to use in combination with the path to the specific resource being consumed.
  • proxy.type: This is the type of proxy, which when dealing with the server will likely be ajax or rest. We know that our customer has a REST API, so it's set to rest.
  • proxy.url: This uses all the preceding options to build a URL. The segments in curly brackets will be replaced in order to build a full URL to the resource being consumed. {prefix} is the urlPrefix from above, {entityName:uncapitalize} is the model's name parsed from the class name without the namespace in lower case.

Phew! At this point, we've done a pretty deep dive into Ext JS configuration options. This chapter, and indeed this book, is supposed to be about architecture. So from now on, there will be some cases where we'll skip over this kind of detail on the assumption that you've worked with Ext JS before and understand these configuration options.

We're trying to design this application; we're not trying to teach JavaScript or Ext JS. Although, we'll look at aspects of the Ext JS framework that contribute to a successful application, we're not going to regurgitate the Sencha documentation. With this in mind, let's add a little bit more to our model and talk about how it helps us meet the customer requirements:

Ext.define('ArchitectureCms.model.Page', {
    extend: 'Ext.data.TreeModel',
    clientIdProperty: 'clientId',
    identifier: {
        type: 'sequential',
        prefix: 'Unsaved-'
    },
    schema: {
        namespace: 'ArchitectureCms.model',
        urlPrefix: 'http://localhost:3000',
        proxy: {
            type: 'rest',
            url: '{prefix}/{entityName:uncapitalize}'
        }
    },
    fields: [
        { name: 'body' },
        { name: 'stub' },
        { name: 'text' },
        { name: 'published' }
    ]
});

This is the final iteration of the Page class, now with an identifier configured. We know that we need to differentiate between a saved and an unsaved model, and we know that the server will return clientId if it's supplied, so here we explicitly state that it's going to have the Unsaved- string in the ID until the server supplies an auto-incremented identifier to replaced it on save.

A model store

The store for this application is pretty simple:

Ext.define('ArchitectureCms.store.Pages', {
    extend: 'Ext.data.TreeStore',
    model: 'ArchitectureCms.model.Page',
    alias: 'store.pages',
    root: {} // set empty root as using bind doesn't do this
});

Everything here is self-explanatory, although there is a caveat. With the current version of Ext JS (5.0.1), we need to set an empty root node that allows you to use data binding to bind this store to a UI component. If we don't, an error will be thrown, so this is a simple workaround.

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

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