Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / docs / guides / tasks_tutorial / README.js
diff --git a/docs/guides/tasks_tutorial/README.js b/docs/guides/tasks_tutorial/README.js
new file mode 100644 (file)
index 0000000..c441f87
--- /dev/null
@@ -0,0 +1,3 @@
+Ext.data.JsonP.tasks_tutorial({
+  "guide": "<h1>Ext JS 4 by Example: Task management application</h1>\n\n<h2>I. Introduction</h2>\n\n<p>Ext JS is a Javascript framework for creating rich web applications supporting browsers all the way from IE 6 to the latest versions of Chrome. It it a large framework consisting of many parts, including application management, layouts, theming, build tools and a large number of components from buttons and form elements to grids, trees and charts.</p>\n\n<p>Looking at the framework for the first time can be a daunting task due to its size and complexity. Although Ext JS is distributed with hundreds of examples and many guides, understanding how all the components fit together in a large application can be difficult, especially for new developers.</p>\n\n<p>In this tutorial we will guide you to build a Task Management application from scratch. We assume you are already familiar with HTML, CSS and Javscript, but <em>not</em> the <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> JS framework. Perhaps you have used simple DOM based Javascript frameworks such as jQuery or Mootools.</p>\n\n<p>We will show you the typical workflow an experienced developer would follow when creating a new <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> JS project.</p>\n\n<p>Below is a <em>30 second video</em> demonstrating the application we will build. You can interact with a live version of the finished application by clicking <em>here</em>. You can download a zip file with the completed application <em>here</em>, or checkout the Git repository and follow along <em>here</em>.</p>\n\n<h2>II. Getting Started</h2>\n\n<h3>1. Setup, Download and Installation</h3>\n\n<p><strong>Copy section 2.1 from the Ext4 Getting Started Guide</strong></p>\n\n<h3>2. Create your application structure</h3>\n\n<p>Before we begin writing code, we'll need to create a directory for our project and copy the relevant resources from the <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> JS distribution. We'll also create empty directories to organize the code we'll be writing.</p>\n\n<ol>\n<li>Create a new folder called <code>tasks_tutorial</code> accessible by your local web server.</li>\n<li>Create the following directories inside <code>tasks_tutorial</code></li>\n<li>Copy the following files from your <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> 4 distribution</li>\n<li>Create your index.html file</li>\n</ol>\n\n\n<p>You now have your application skeleton. All new <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> projects should begin this way.</p>\n\n<h3>3. The Ext class</h3>\n\n<p><code>Ext</code> is the only global variable used by <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> JS. It serves as a namespace containing all the <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> components and classes. It also contains a number of alias methods for common functions. For example <code>Ext.getCmp</code> is an alias for <code>Ext.ComponentManager.get</code>. Related classes are often grouped within namespaces on the <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> object, for example you'll find all the charting related classes in the Ext.chart namespace.</p>\n\n<h3>3. Define the Application</h3>\n\n<p>Every <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> JS 4 application starts with an instance of the <a href=\"#/api/Ext.app.Application\" rel=\"Ext.app.Application\" class=\"docClass\">Ext.app.Application</a> class. The Application contains global settings for your application (such as the app's name), as well as maintaining references to all of the models, views and controllers used by the app.</p>\n\n<p>In the root project folder <code>tasks_tutorial</code>, create a file called <code>app.js</code>:</p>\n\n<pre><code>Ext.application({\n    name: 'Tasks'\n});\n</code></pre>\n\n<p>This will create a global variable called <code>Tasks</code> under which all of our application's code will reside. This keeps the global namespace clear which will ease integration with any other Javascript libraries we may wish to use in the future.</p>\n\n<h3>4. Define the Viewport</h3>\n\n<p>The Viewport contains everything visible inside the browser window. By default, an <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> application will look for a file inside the app/view directory called <code>Viewport.js</code> which contains the viewport configuration. Think of it as the root container of everything you see in your browser window.</p>\n\n<p>Create a file called Viewport.js inside app/views with the following content:</p>\n\n<pre><code>Ext.define('Tasks.view.Viewport', {\n    extend: 'Ext.container.Viewport',\n    html: 'Tasks Application'\n});\n</code></pre>\n\n<p>At this point we'll also need to include a line in our app.js file to render the viewport automatically when the application starts up:</p>\n\n<pre><code>Ext.application({\n    name: 'Tasks',\n    autoCreateViewport: true\n});\n</code></pre>\n\n<p>We now have all the pieces in place to display something in the browser. Fire up your favorite development browser (we recommend the latest version of Google Chome) and navigate to the root folder of your application (eg http://127.0.0.1/tasks_tutorial). You should see a white screen with the text 'Tasks Application' at the top left:</p>\n\n<pre><code>SCREENSHOT\n</code></pre>\n\n<h2>III Displaying a List of Tasks</h2>\n\n<h3>1. Models</h3>\n\n<p>Our ultimate goal is to create an application that allows users to create, update and manage a list of tasks. First of all, we need to define what a 'task' actually is as well as the information that will be associated with one. In Ext JS we call this 'Modeling' our data. A Model is a representation of an object and contains a collection of attributes called 'fields'.</p>\n\n<p>For our purposes, a task should have the following fields:</p>\n\n<ul>\n<li>Title (eg Do Laundry)</li>\n<li>Category (eg Chores)</li>\n<li>Due date (eg 06/08/2011)</li>\n<li>Status (eg Incomplete)</li>\n</ul>\n\n\n<p>Lets start by creating a new file in app/model called Task.js:</p>\n\n<pre><code>Ext.define('Tasks.model.Task', {\n    extend: 'Ext.data.Model',\n    fields: [\n        { name: 'title' },\n        { name: 'category' },\n        { name: 'dueDate', type: 'date'},\n        { name: 'status' }\n    ]\n});\n</code></pre>\n\n<p>Great! But before we can create a new task, we'll need somewhere to store it. In Ext, a Store encapsulates a collection of Model objects.</p>\n\n<p>Lets create a new Store for our Tasks and put it in app/store/Tasks.js:</p>\n\n<pre><code>Ext.define('Tasks.store.Tasks', {\n    extend: 'Ext.data.Store',\n    model: 'Tasks.model.Task',\n\n    proxy: {\n        id  : 'tasksStore',\n        type: 'memory'\n    },\n\n    data: [\n        { title: 'Laundry', category: 'Chores', dueDate: '01/06/2011', status: 'complete' },\n        { title: 'Science project', category: 'School', dueDate: '02/06/2011', status: 'incomplete' },\n        { title: 'History assignment', category: 'School', dueDate: '03/06/2011', status: 'incomplete' }\n    ]\n});\n</code></pre>\n\n<p>A <code>proxy</code> defines <em>where</em> we want to store the data. This could be in memory (as in this case) or we could store the data on a server, or perhaps in LocalStorage (on modern, HTML5 compliant browsers). We'll look at proxies in more detail later.</p>\n\n<p>As you can see we've pre-populated our Store with some dummy data. Later on, we'll replace this with live data.</p>\n\n<h3>2. Views</h3>\n\n<p>Ok, so we modeled a task and created a store with some dummy data. Lets see if we can view our data in a grid.</p>\n\n<p>In <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> JS, view related code is stored in the app/view directory. We usually group views in directories relating to their Controller (which we'll talk about shortly).</p>\n\n<p>Lets create a file called app/views/tasks/List.js:</p>\n\n<pre><code>Ext.define('Tasks.view.tasks.List', {\n    extend: 'Ext.grid.Panel',\n    alias: 'widget.taskList',\n    store: 'Tasks',\n\n    title: 'My Tasks',\n\n    columns: [\n        { header: 'Done',     dataIndex: 'status', width: 50, align: 'center', resizable: false },\n        { header: 'Title',    dataIndex: 'title',  flex: 1 },\n        { header: 'Category', dataIndex: 'email'           },\n        { header: 'Due Date', dataIndex: 'dueDate'         }\n    ]\n});\n</code></pre>\n\n<p>Here we define a Grid and tie it to our Tasks store. That is where the data will be fetched from when it is time to render the grid. We defined some columns and associated them with their corresponding data index (the field name from the Task model).</p>\n\n<p>Lets update Viewport.js and replace our dummy text with our newly defined tasks grid:</p>\n\n<pre><code>Ext.define('Tasks.view.Viewport', {\n    extend: 'Ext.container.Viewport',\n    layout: 'fit',\n\n    items: {\n        xtype: 'taskList'\n    }\n});\n</code></pre>\n\n<p>An <code>xtype</code> is a shorthand way of referring to a component. All of the components that ship with <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> JS have an xtype. Examples include <code>button</code>, <code>panel</code>, <code>grid</code>, <code>checkbox</code> and <code>chart</code>. We assigned an xtype of <code>taskList</code> to our List view with the line <code>alias: 'widget.taskList'</code>.</p>\n\n<p>Containers in <a href=\"#/api/Ext\" rel=\"Ext\" class=\"docClass\">Ext</a> JS have an <code>items</code> config option which list a single child object or array of child objects. For now we just want to display our Grid of tasks, so we use the singular form.</p>\n\n<h3>3. Controllers</h3>\n\n<p>Controllers are the glue that binds an application together. They respond to events and take some action. These events might be, for example, a user clicks a button or the browser window is resized. The actions taken usually involve updating the view of the application, for example popping up a message box or resizing a component.</p>\n\n<p>We'll need to create a Controller so that our application is aware of our model, store and view. Later we'll extend this controller to take actions on events, such as when we click a 'New Task' button.</p>\n\n<p>Create a file app/controller/Tasks.js:</p>\n\n<pre><code>Ext.define('Tasks.controller.Tasks', {\n    extend: 'Ext.app.Controller',\n\n    models: ['Task'],\n    stores: ['Tasks'],\n\n    views: ['tasks.List']\n});\n</code></pre>\n\n<p>We'll also need to make our application aware of this controller. Update app.js:</p>\n\n<pre><code>Ext.application({\n    name: 'Tasks',\n    autoCreateViewport: true,\n\n    controllers: ['Tasks']\n});\n</code></pre>\n\n<p>OK! We should now be able to refresh our browser window and see a list of tasks nicely formatted in an Grid Panel.</p>\n\n<h2>IV. Adding a New Task</h2>\n\n<h3>1. Create a New Task button</h3>\n\n<p>Lets add a button we can use to create new tasks. We'll put this in a toolbar at the top of the Tasks grid. Open up app/view/tasks/List.js and add the following code under the line that read <code>title: 'Tasks'</code> (append a comma after <code>title: 'Tasks'</code> to keep the javascript valid):</p>\n\n<pre><code>dockedItems: [{\n    xtype: 'toolbar',\n    dock: 'top',\n    items: [\n        { xtype: 'button', text: 'New Task' }\n    ]\n}]\n</code></pre>\n\n<p>That will create a toolbar docked to the top of the Grid panel containing a single <code>button</code> component. Try refreshing your browser to see the result.</p>\n\n<p>Next we'll want to link this button to an action so something happens when someone clicks it. Open up app/controller/Tasks.js and add the following code under the line that reads <code>views: ['tasks.List']</code> (remembering the extra comma):</p>\n\n<pre><code>init: function() {\n    this.control({\n        'taskList &gt; toolbar &gt; button': {\n            click: this.newTask\n        }\n    });\n},\n\nnewTask: function() {\n    alert('New Task!')\n}\n</code></pre>\n\n<p>The <code>control</code> method attaches listeners to components identified by selectors. The selector targets a component using <a href=\"#/api/Ext.ComponentQuery\" rel=\"Ext.ComponentQuery\" class=\"docClass\">Ext.ComponentQuery</a>. The interface is very similar to CSS selectors. In the code above, we target the button with the selector <code>taskList &gt; toolbar &gt; button</code>. We then attach a listener to the <code>click</code> event and bind it to the <code>newTask</code> function.</p>\n\n<p>The result is that when the button is clicked an alert box is created with the next 'New Task!'.</p>\n\n<h3>2. Display a New Task form</h3>\n\n<p>We want to create a popup that displays a form with fields for creating a new task when a user clicks the 'New Task' button. Create a new file <code>app/view/tasks/Form.js</code>:</p>\n\n<pre><code>Ext.define('Tasks.view.tasks.Form', {\n    extend: 'Ext.window.Window',\n    alias: 'widget.newTask',\n\n    title: 'New Task',\n    resizable: false,\n\n    bodyPadding: 20,\n    html: 'New Task Window'\n});\n</code></pre>\n\n<p>Update the <code>views</code> config option in <code>app/contoller/Tasks.js</code> to include this new view:</p>\n\n<pre><code>views: [\n    'tasks.List',\n    'tasks.Form'\n],\n</code></pre>\n\n<p>Also update <code>app/controller/Tasks.js</code> to show the window when the user clicks the New Task button:</p>\n\n<pre><code>newTask: function() {\n    Ext.create('Tasks.view.tasks.Form').show();\n}\n</code></pre>\n\n<p>Try refreshing your browser to test it out. Now lets replace the html content with some fields. In <code>app/view/tasks/Form.js</code>, replace these lines:</p>\n\n<pre><code>bodyPadding: 20,\nhtml: 'New Task Window'\n</code></pre>\n\n<p>with the following:</p>\n\n<pre><code>items: {\n    xtype: 'form',\n    bodyPadding: 10,\n    border: false,\n    items: [\n        {\n            xtype: 'textfield',\n            fieldLabel: 'Title',\n            name: 'title'\n        },\n        {\n            xtype: 'textfield',\n            fieldLabel: 'Category',\n            name: 'category'\n        },\n        {\n            xtype: 'datefield',\n            fieldLabel: 'Due Date',\n            name: 'dueDate'\n        }\n    ]\n},\n</code></pre>\n\n<p>This creates a form with the 3 new fields required to add a new task. The <code>layout: 'fit'</code> config option means the form will automatically stretch if the New Task window is resized. Test it out in your browser.</p>\n\n<h3>3. Storing the new task</h3>\n\n<p>Lets create 'Save' and 'Cancel' buttons on our New Task form. Edit <code>app/view/tasks/Form.js</code> and add this code below your <code>items</code>:</p>\n\n<pre><code>buttons: [\n    {\n        text: 'Save',\n        action: 'save'\n    },\n    {\n        text: 'Cancel',\n        action: 'cancel'\n    }\n]\n</code></pre>\n\n<p>We've defined <code>action</code> parameters on our buttons which we will use to target these components. Lets make the cancel button close the window. Edit <code>app/view/controller/Tasks.js</code> and add this code to your <code>this.control</code> method:</p>\n\n<pre><code>'newTask button[action=cancel]': {\n    click: function(btn) {\n        btn.up('newTask').close();\n    }\n}\n</code></pre>\n\n<p>When the user clicks the Cancel button, the click handler is run. The click handler is passed a reference to the 'Cancel' button. We use the <code>up</code> method on this component to find the closest ancestor with an id of <code>newTask</code>, which happens to be the New Task window. Now that we have a reference we can call <code>close</code> to close the New Task window.</p>\n\n<p>Now lets add a handler for the Save button. Add this code under the code you just wrote (don't forget your commas!):</p>\n\n<pre><code>'newTask button[action=save]': {\n    click: this.saveTask\n}\n</code></pre>\n\n<p>Now lets add the <code>saveTask</code> method at the bottom of our Tasks controller:</p>\n\n<pre><code>saveTask: function() {\n    console.log(this.getNewTaskForm().getValues());\n}\n</code></pre>\n\n<p>Wondering where that <code>getNewTaskForm()</code> method came from? As it happens it doesn't exist yet, so lets create it. Under you <code>views</code> config option, add this code:</p>\n\n<pre><code>refs: [\n    {\n        ref: 'newTaskForm',\n        selector: 'newTask &gt; form'\n    }\n]\n</code></pre>\n\n<p>The <code>refs</code> config option exists so you can define references to components on the page. This will create a helper method, in this case <code>getNewTaskForm</code> which is available from methods on your controller by calling <code>this.getNewTaskForm()</code>. So now we have an easy way of getting a reference to our New Task form from any method in our Tasks controller.</p>\n\n<p>Save your work and refresh your browser. When you click the 'Save' button on the New Task form you should see an object containing the values from the form in your browser's console window.</p>\n\n<p>Now we just need to create a new Task from these values and add them to our Tasks store. Edit the <code>saveTask</code> method like this:</p>\n\n<pre><code>saveTask: function(btn) {\n    var task = Ext.create('Tasks.model.Task', this.getNewTaskForm().getValues()),\n        store = this.getStore('Tasks');\n\n    store.add(task);\n    btn.up('newTask').close();\n}\n</code></pre>\n\n<p>Refresh your browser and try adding a task. You should see it get added to the grid when you click Save.</p>\n\n<h3>4. Validating your fields</h3>\n\n<p>One problem with the New Task form is that values can be left blank. Lets add some validations so that each field must be filled in.</p>\n\n<p>Add the following code under your <code>fields</code> in <code>app/model/Task.js</code>:</p>\n\n<pre><code>validations: [\n    { type: 'presence', name: 'title' },\n    { type: 'presence', name: 'category' },\n    { type: 'presence', name: 'dueDate' }\n]\n</code></pre>\n\n<p>This adds validations to the Task model. These validations check for the presence of the <code>title</code>, <code>category</code> and <code>dueDate</code> fields.</p>\n\n<p>Now we need to update our <code>saveTask</code> method to check the Task is valid before adding it to the Store. If it is <em>not</em> valid, we need to show the error messages on the form. Update the <code>saveTask</code> method to the following:</p>\n\n<pre><code>saveTask: function(btn) {\n    var formValues = this.getNewTaskForm().getValues(), // A hash of\n        task = Ext.create('Tasks.model.Task', formValues),\n        store = this.getStore('Tasks'),\n        errors = task.validate(),\n        fields = this.getNewTaskForm().getForm().getFields();\n\n    if (errors.isValid()) {\n        store.add(task);\n        btn.up('newTask').close();\n    } else {\n        fields.each(function(field) {\n            var fieldErrors = errors.getByField(field.getName()),\n                errorMessages = Ext.Array.pluck(fieldErrors, \"message\");\n\n            field.markInvalid(errorMessages);\n        });\n    }\n}\n</code></pre>\n\n<p>We also want our error messages to appear underneath the fields by default. Add these lines to the <code>items</code> config in <code>app/views/tasks/Form.js</code></p>\n\n<pre><code>fieldDefaults: {\n    msgTarget: 'under'\n}\n</code></pre>\n\n<p>Try refreshing your browser and adding an invalid task to see the result.</p>\n\n<h2>V. Marking a Task Complete</h2>\n\n<h3>1. Adding a Checkbox</h3>\n"
+});
\ No newline at end of file