ExtJS 4.2 Walkthrough — Part 4: Steppin’ in Some CRUD

We’ve finally arrived! After some setup, a bit of layout work, the creation of our first controller, a full version upgrade and even a bug fix, we’re ready to get into the heart of our application…specifically, interacting with data from our server. In order to do this, we’ll need to explore the concepts of Models, Stores and Proxies, as well as creating a new controller and even a fancy data grid with inline editing capability.

We’re in for a long haul in this installment, but it’s worth it. When we come out the other side, we’ll not only have real functionality working in our app, but we’ll also have covered some very important concepts that will let us ramp up our development of the rest of the application. Ready? Let’s do it.

Data Models

As a developer, you’ve no doubt utilized data models on a regular basis. They are handy things, for not only do they let you describe objects via their properties and relationships, but they also semantically describe your application. In ExtJS, the Ext.data.Model fills this role, providing a really nice way to manage objects which can be grouped together in caches (a Store) and, more interestingly or even bound to model-aware components like the Ext.grid.Panel

Especially in the domain of managing data coming from the server, the Model is a crucial means of translating the raw stream of content returned from the server into an object that your ExtJS app can leverage to do some pretty awesome stuff.

Simple Example

So let’s start with a very simple example. In our application, we’re going to have several tables in our database which are “option” or “lookup” tables. Consider, for example, the Color lookup table which stores options for car colors:

To model this data in our app, we simply need to define an Ext.data.Model that will translate the data we send from the server into an object that ExtJS can use. Here’s an example of our potential model:

First, our data model extends Ext.data.Model. By doing this, we gain access to a TON of really helpful methods and properties that will help us manage our model instances. Be sure to memorize the docs on this one.

Whether or not the property is persistent (if false, it won’t be sent back to the server, ever)

Default values (if any)

By default, field names map 1-to-1 with the keys of the data structure retrieved from the server. So, in order to populate this model with data from the server, we would expect to see the following in the response:

Extensible Models

While we could plunk this Model in our app without any issues, we’ll take a bit of a longer view from the start. Namely, if we look at this data model, we might see some potential for abstraction:

CreatedDate and Active are going to be used on EVERY TABLE in our database.

LongName and ShortName are going to be used on every OPTION table in our database

Since specifying these properties on every single data model in our application would be redundant, we’ll expand on our policy of abstraction, and create some base models that we can reuse as we expand our app.

Pretty simple. Just a base, abstract model that specifies the common properties that every one of our models will inherit.

Next, since all of our option tables share common properties, let’s make another, higher-level abstract model that all of our option models can use. In the model folder, first create a new folder called option. Next, create a new file named Base.js:

Very straightforward. Now that we’ve abstracted, we have a new Color model that, while still retaining precisely the properties as were defined in the original example, is better constructed. Not only will this let us write less repetitive code when we create other option models, but it will also save us a lot of headaches if we need to add another shared property…instead of updating each and every file, we can just update the one base model. And finally, if we ever need to make one of the options divergent from the others, that’s still possible since we’ve subclassed each option model. Beautiful.

Testing Our Model

Let’s take our new model for a test drive. To do this, open your browser, load this application, and go into Web Developer or Firebug. In the console, enter the following:

After running the command, you should see something like the following:

As you can see, we have created a new instance of our CarTracker.model.option.Color model, and pre-populated it with a bit of data. Now that our raw data (the object we passed to the creation of the model instance) has been converted into a legit model, we can call any of the built-in methods that Ext.data.Model affords.

Moving On

As great as creating our first model has been, it doesn’t do us a lot of good yet. After all, we’re not really interested in creating model instances like this: we want them to be populated with data coming from the server. While we could certainly configure our model to do just that, a more common way of managing models is via a store. So let’s turn our attention there now.

Our First Store

At its most basic level, a store is simply a cache of model instances within your app. But it’s so much more! Not only is it one of the most common gateways for interacting with the server within ExtJS apps, but it is also a powerful object that can be wired to a large number of data-aware components. For example, let’s say we have a data grid with a column for each property in our model. If we take a store which has been configured with the particular model and wire it up to the grid, the grid will automatically render a row for each model in our store, matching the properties in the store’s model to the columns in the grid. What’s more, if the data in our store changes, these will be automatically communicated to the grid, and the displayed data will update to represent the change. This is game changing, since you can really turn your attention to more interesting aspects of your application and just let this awesomeness do its thing.

Enough talk; let’s make one.

As we saw when setting up our application, Sencha Cmd automatically created a store folder in our application’s app folder. This is where we will create all of our stores. As with our views and models, we’ll want to be smart about packaging our stores so that our file organization doesn’t suck.

Since we’re creating a store for our Color model, let’s go ahead and create a new folder called option in the store folder, and then create a new file called Colors.js:

NOTE: While not required by any means, a common convention for naming stores is to use the plural form of the model name. So if our model is Store.js, the store would be Stores.js. The idea is that since a model represents a single instance, and the store represents a collection of model instances, the plural fits.

alias: As with components, we can alias our stores. Instead of “widget”, however, we use “store” as the prefix

requires: Here, we’re requiring the model that we want to use for this store in order to make sure it’s loaded before our store tries to use it

storeId: Not required, but a nice way to uniquely identify the store. Plus, if we specify a storeId, this store will automatically be registered with Ext.StoreManager, making it easier to reference later

model: The full class path to the model we’d like to use with the store (notice the correspondence with requires[]….)

remoteFilter: If true, we’ll do all our filtering via SQL/or other server-side mechanism…a must if our result set is “paged”

remoteSort: If true, we’ll do all our sorting via SQL/or other server-side mechanism…a must if our result set is “paged”

proxy: The proxy our store will use for communicating with the server…more below

Getting Data to Our Store

Before we can test our Store, we need to make sure that our application server is prepared for the request. There are two main things to consider.

Request URL

In the proxy config, you can see that we’ve specified both a type of “rest” and a url of “/api/option/colors”. The URL can be whatever you want it to be, but the type of proxy is important. With the “rest” proxy (Ext.data.proxy.Rest), ExtJS will dynamically build the request URL based on the type of request being made. So assuming that our url is configured as above, the normal CRUD urls that ExtJS creates will be:

read: /api/option/colors.json (GET)

create: /api/option/colors.json (POST)

update: /api/option/colors/{id}.json (PUT)

delete: /api/option/colors/{id}.json (DELETE)

As you can see, with the REST-style proxy, the same URL is being used for each request. The only difference is the HTTP verb sent, as well as the ID property of the model instance in the case of updates and deletes.

With this is in mind, we’ll need to make sure that our server will accept these types of requests and that our application server (ColdFusion, PHP, .NET, whatever) is configured to properly route the requests to the same URL based on the HTTP verb and existence of the ID value.

Handling the Response

Assuming that our server has properly handled the request, we also need to ensure that the data is returned to our Store in a way that it can handle. While there are a number of formats that the Ext.data.reader.Reader can accomodate, the most used is the Ext.data.reader.Json. For our purposes, the configuration of this reader revolves around two configurations: root and totalProperty. The root config instructs the Reader where it should begin looking for data within the JSON-formatted response. In our example, we’ve specified that it should look in a key called “data”. Next, we specify that the totalProperty for our result set can be found at the “count” key. This will let our store know the total number of records that exist in our data, which is especially helpful when using techniques for paging (e.g., the total data set size is known, but only a partial set is returned at a time).

Putting this all together, our response from the server should look something like:

The Test

First, we create a new instance of our Store. Next, we call the load() method which will kick off a remote request to the server (assuming everything is configured correctly). Once the response is received, run the following:

colorStore.getCount()

Assuming that you had data to return, this should print the total number of model instances in the store.

We now have a store that can manage our model instances, and this store is successfully communicating with the server. Awesome.

Of course, there is some refactoring and abstracting that we’ll want to do. But since we’ve come so far, let’s reward ourselves by pressing on and attaching our store to something that we can actually use.

The Option Grid

Now that we have our first Model and Store, we can start using them within our application to make some cool stuff. Our first objective is to make a management console for our Color options. While there are a lot of ways we can approach this, a pretty shiny one is to create an editable grid that will not only allow us to display all of the data, but will also let us create, edit and delete records…all in the same view. When we’re finished, it should look kind of like this:

A Fancy Editable Grid

Let’s create the grid. In view, create a folder named option, and then a new file called List.js:

By now, we’ve created a number of components, so this should look familiar. I’ll only point out a few items of interest:

requires[]: This grid will utilize a special plugin (Ext.grid.plugin.RowEditing) and a special toolbar (Ext.toolbar.Paging). As with our other components, we want to make sure that these classes are loaded before we use them

plugins[]: We use the plugins[] config to define the plugins to be used by our component. In this example, our grid is using the Ext.grid.plugin.RowEditing plugin, which can be initialized via its ptype “rowediting”

dockedItems[]: This allows us to configure items that will be “docked” to our component, which essentially binds them in place to their configured position (top, left, right, bottom). In this example, we have a top toolbar with some buttons, and on the bottom we have a toolbar to manage paging of our recordset.

Displaying the Grid

Now that are grid is defined, we need a way to display it. In our view/layout/Menu.js file, let’s change the “Options” button to have a sub-menu. This will let us put all of our “option” links in one place and not take up space in our navigation menu.

We specified an xtype of “option.list”. If you remember, we gave our grid the same xtype. Therefore, when this component is rendered, a new instance of our grid will be created and placed into the center region of our app.

We configured this instance of our grid to use a store via Ext.create(…). One benefit of this approach is that it allows us to override configuration of the store for the particular instance. In this case, we are setting a pageSize of 30.

A New Controller

As we discussed earlier, it’s ideal for us to create controllers for each main section of our application. While we could create a separate Colors controller, we’ve already discussed that our Color model really only represents a specific implementation of a more generic Option model. Since all options will have the same data structure, it also makes sense that we manage them in the same way as well. Therefore, instead of creating a specific Colors controller, we’ll settle for a more general Options controller.

NOTE: The beauty of ExtJS MVC-style is that we can always subclass Colors if we want/need to. That is, if the needs of the Color model diverge from what Option can reasonably accomodate, we can always create a controller that extends the Options controller, or create a new one altogether.

Since there’s so much going on here, I’m not going to go into a huge amount of detail. If you follow the logic, however, we’ve implemented logic for viewing the records (loadRecords), creating new data (add), editing data (save) and deleting data (remove). We’ve also let our controller know about the Colors store (stores[] config), our grid (views[] config), and have set up a number of listeners within init() to handle the various events that will occur while managing the data for this particular store and grid.

Wiring Up Our Controller

The very last thing we need to do is to let our app know about our new controller. To do this, let’s open app.js and add our controller to the controllers[] config:

That’s all there is to it. If everything is implemented correctly, we should be able to reload our app in the browser and see the awesome new functionality. Hooray!

Some Refactoring

There is no rest for the wicked! Our new functionality looks awesome, but we know there’s some refactoring we should do. Let’s get to it.

An Abstract Proxy

First, let’s refactor our proxy. If you remember above, we more or less hard-coded our proxy configuration onto our Colors store. While this obviously works, it’s definitely not great since we’d have to duplicate that proxy config over and over for each and every store. What would be better would be to create an abstract proxy that we can simply use anywhere it’s needed. To do this, let’s start by creating a folder named proxy at the root of our app. In this proxy folder, let’s also create a file called Rest.js:

Very straightforward. We’ve more or less moved the proxy config off of the Colors store, and wrapped it into a new class. Notice that we also gave it an alias of “baserest“–this is what we’ll use when applying it to our stores.

A Base Store

You knew it was coming. Since we don’t want repeat ourselves over and over when defining stores, let’s create an abstract Store in the store folder called Base.js:

Again, we have more or less applied much of our Colors store config and created a base class out of it. Notice, though, that we are requiring the custom Proxy that we created, and then using it within the proxy config of our store.

Another thing to notice is the custom restPath config. This will allow us to specify a custom URL on our individual store instances, which will be then be applied to our proxy’s url config. This is especially useful if your ExtJS application is not at the webroot, and needs to specify some kind of root URL to which the restPath is appended.

A(nother) Base Store

This one’s definitely not necessary, but since our Colors store is really an implementation of an idea of an “option”, let’s go ahead an make an abstract store within the option package called Base.js. At the moment, it won’t have anything specific in it besides a custom sorter, but may prove even more useful later on as the specificity and requirements of our applications grows:

Beautiful. Now our Colors store is only configuring options that are specific to itself, and allowing the inheritance of its parent classes to take care of the rest.

Wrapping Up…and Some Homework

Phew! That was epic. In that whirlwind of development, we made data models, implemented stores and proxies, and even created a super-fancy editable grid. But best of all, in the process of working through this, we’ve covered a lot of topics that will be incredibly useful to us as we move forward and start developing more functionality.

But before we continue, you have some homework

Before the next installment, go ahead and finish out the rest of the options. Once finished, you should have the following options available:

Categories

Colors

Features

Positions

Statuses

Each of these should appear in the “Options” menu on the interface, and selecting any of the options should load the Option Management grid with the appropriate data from the server (you’ll have to make that). Have fun!

RE: the root issue, that’s a combination of how your site is setup and how the URLs in Ext JS are defined. In the CarTracker source, all store URLs (or restPath) are relative to the site root (e.g., ‘/api/cars’). This setup will always produce urls that are “rooted” to the base of the site. To use this, I setup a virtual host for my site called “cartracker.dev”. This lets me access the site like so: http://cartracker.dev, and produces API urls like http://cartracker.dev/api/…

If you need to access your site as a subdirectory of the site root, you can specify a global variable in your index.html file and set the full proxy root there. For example, before the inclusion of app.js, add something like so:

var APPLICATION_PROXY_ROOT = "http://127.0.0.1:8500/cartracker" // or whatever the path you're using looks like

I was working through this walk through at a great pace until I hit this section. I work on a dev team and primarily do front end work web work. In fact I have only been doing professional web development for less than a year. I’m kind of at a loss on how to set up the server side to this project. It seems to me that it might not be an extremely simple task? I’m really not even sure where to start.

Did I miss a section in this project that had to do with data/server set up?

Should I just be able to assume the set up of the server/tables/database based on what I’ve done in the front end?

Obviously there is a lot of code that I can see on GitHub that isn’t included in this part of the walk through, should that be my main point of reference to finish this section?

Please don’t take this next question the wrong way but: Isn’t the “data” portion of this walk through a reasonably extensive and important aspect of this project as a whole? Is this(server/data) something that I (as a Jr web developer) should be able to just throw together in an afternoon while doing this walk through? Is this not like a whole project within a project?

I’m just trying to put a scope on this thing. For example if you respond and say its not too extensive of a set up, I’ll know it could take me any where from maybe a day to a week to figure out. But if you say its reasonably extensive, given my almost complete lack of prior server side development, then I’ll know it may take me much more than a week to work out the kinks.

I would greatly appreciate any advise on where to start looking(guides?) and perhaps a list of requirements that this portion of the project concerns.

You didn’t miss the section on the server setup. As I mention in my introduction to the series, my purpose in doing this walkthrough was to specifically address the Ext JS side of things…I tried to steer clear of the server-side stuff as much as possible (after all, Ext JS doesn’t particularly care what it’s connecting to…).

That being said, you are right: there is a significant amount of work to do on the backend in order to make this a workable project. Definitely not something that could be thrown together in an afternoon, unless of course you’re using the same setup and just drop the repo in your project.

On the other hand, this app does not presume any life-altering server-side code voodoo. It is a pretty straight-forward CRUD type app. So if you are looking for tutorials, you could easily pick your language of choice (PHP, .NET, ColdFusion, whatever) and search for tutorials on creating basic CRUD-style applications, specifically tutorials that focus on heavy AJAX integration.

However, there’s really not much to what the server side needs to be able to do. The short list is basically:

Hi Existdissolve,
I’m trying to learn to code with Ext JS4..
I thank you very much for showing this example that it’s really usefull for understandind Ext.
I have a question: when you create the stores you use the config
restPath: ‘/api/option/colors’,
but I couldn’t find the api directory in your codes on GitHub.
Can you please add this directory in your example project?

First: WOW! What an absolutely INCREDIBLE tutorial! Having made it to the end of this section, I’m almost jumping up and down and clapping excitedly – I’d love to keep going but alas, it is really late and I have work in the morning. Thank you SO much for taking the time to create this. It is far beyond any other ExtJS tutorial I’ve found, and I’ve been through quite a few.

Secondly: I’m learning this to build a document-editor frontend for an existing Oracle Application Express application. I have been informed that setting up a RESTful API is a no-go due to expenses stemming from added security requirements.

I have been using a feature of APEX, “htmldb_get” (which is basically a xhr wrapper) to communicate with PL/SQL code that interfaces with the database – there are no URLs involved, only parameters of the form “APPLICATION_PROCESS=XXX” which executes the PL/SQL function XXX and responds with whatever was output.

Are you familiar with what I am describing at all? Is it possible to create a proxy that will perform CRUD operations by way of parameters to htmldb_get instead of REST get/post/put/delete ?

Any help much appreciated – and congratulations on an exceptional article! I can’t wait to keep going at it tomorrow!

RE: your proxy question, that should be pretty easy to accomplish. If I’m understanding your need correctly, you should be able to utilize the more common Ext.data.proxy.Ajax class (http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.data.proxy.Ajax-cfg-api). You can then use the api config to specify the URL pattern that you’d like to use for each of the CRUD actions.

Hi Existdissolve, thank you so much for this great tutorial, I’m a newbie in EXTJS and I’ve read a couple of books about this framework and they weren’t that good compared to your tutorial, really, great work!.

I’m in this part, and I’m really excited to get to the end of the tutorial, but I’m kind of stucked in this section, I have a problem, the Option controller doesn’t seems to be working, first of all I’m not working with Sencha CMD 3, I’m using version 4, in which it generates a file Application.js in the root of the app folder, but I actually don’t use that file, maybe that could affect my app. When I put the Options controller in the “app.js” file (the one in the root of cartracker folder) on the “controllers :” section, I get an error and the application breaks, the error is “Uncaught TypeError: Cannot read property ‘listen’ of undefined”, but when I comment or remove that controller the application “works” again but without the functionality of the controller, what could be wrong?, thank you very much.

Hi Federico,
I’m using version 4 too.
Just create the Proxy.js file “app/domain/Proxy.js” (see PartFour on github) in your app and change the App name.
Include a “requires” for it in Application.js
requires: [
‘AppBase.domain.Proxy’
],
controllers: [‘App’,’Options’
],

It works for me.

Existdissolve , thank you very much for sharing this knowledge. keep up the good work!

Hi Existdissolve,I want to ask how can I sync many phantom records.I return the saved records with id but it seems ext4.2 can not deal with multiple records return form server.store’s onCreateRecords method is empty in ext4.2 which exsits before ext4.1.I am wondering how ext resolve multiple records return from server and how can I save multiple records?

Thank you very much for putting together this tutorial. It’s very helpful!

I’ve implemented everything up to this point (for the Colors) but for some reason when I double click the first item in the grid and ‘update’ it the changes don’t stick. It works for all the other items in the list except for the very first one. Any thoughts on why that might be?