Jorge Ramon

  • Home
  • New Here?
  • Articles
    • All
    • Sencha Touch
    • jQuery Mobile
    • ExtJS
  • Books
  • About

Sencha Touch 2 Models – hasMany Associations, PHP Example

September 5, 2012 12 Comments

In this article you will learn how to use the hasMany association, a feature of Sencha Touch models that allows you to connect two models in a one-to-many relationship. The model configs you will learn about in this post are the following:

  • hasMany
  • belongsTo

The back-end code for this tutorial is in PHP. I also published a version of this Sencha Touch tutorial using C#

Let’s create a simple Sencha Touch application with the following files:

In the model/Hotel.js file, you will define a Hotel model like so:

Ext.define('App.model.Hotel', {
    extend: 'Ext.data.Model',
    config: {
        fields: [
            { name: 'id', type: 'int' },
            { name: 'name', type: 'string' },
            { name: 'address', type: 'string' },
            { name: 'status', type: 'int' }
        ],
        hasMany: {
            model: 'App.model.Room',
            name:'rooms'
        }
    }
});

The interesting part of this model definition is the hasMany config, consisting of the model and name properties, which reference a Room model. You will create this model in the model/Room.js file:

Ext.define('App.model.Room', {
    extend: 'Ext.data.Model',
    requires: ['Ext.data.Store'],
    config: {
        fields: [
            { name: 'id', type: 'int' },
            { name: 'floor', type: 'string' },
            { name: 'type', type: 'string' },
            { name: 'standardRate', type: 'float' },
            { name: 'smoking', type: 'string' },
            { name: 'status', type: 'int' },
            { name: 'hotelId', type: 'int'}         // This works with belongsTo property below.
        ],
        belongsTo: {
            model: 'App.model.Hotel',
            foreignKey: 'hotelId'
        },
        proxy: {
            type: 'ajax',
            api: {
                create: '../../services/rooms.php?act=createrooms',
                read: '../../services/rooms.php?act=loadrooms',
                update: '../../services/rooms.php?act=updaterooms',
                destroy: '../../services/rooms.php?act=eraserooms'
            },
            reader: {
                rootProperty: 'hotels'
            }
        }
    }
});

This model has a belongsTo config, with the model and foreignKey properties, which reference the Hotel model. It also has a proxy config, which references the services/rooms.php page.

This is the code for the rooms.php page:

// Class to represent a hotel.
class Room {
      function __construct($id, $floor, $type, $standardRate, $smoking, $status, $hotelId) {
 		$this->id = $id;
		$this->floor = $floor;
		$this->type = $type;
		$this->standardRate = $standardRate;
		$this->smoking = $smoking;
		$this->status = $status;
		$this->hotelId = $hotelId;
	}
}

$action = $_GET["act"];

$result = "{'success':false}";

switch($action) {

	case "updaterooms":

		$roomJson = file_get_contents('php://input');
		$rooms = json_decode($roomJson);

		// Here you would save the rooms to the database...

		// Returning success for demo purposes.
		$result = "{'success':true,'rooms':" . json_encode($rooms) . "}";

		break;

	case "loadrooms":

		$filterJson = $_GET["filter"];
		$filter = json_decode($filterJson);

		// The value of $filter[0]->property should be "hotelId" for rooms associated to a hotel.
		// The value of $filter[0]->value should be the id of the hotel to which the rooms are associated.
                // Here you would load the rooms for the given hotelId from the database.
                // We are returning hard-coded results for demo purposes.
		$result = "{'success':'true','rooms':[{'id': 1, 'floor': '3', 'type': 'Royal Suite', 'standardRate': '2', 'smoking': 'false', 'status': '1', 'hotelId': '1'}]}";

		break;

	case "createrooms":

		$roomJson = file_get_contents('php://input');
		$rooms = json_decode($roomJson);

		// Here you would save the rooms to the database...

        // Returning success for demo purposes.
		$result = "{'success':true,'rooms':" . json_encode($rooms) . "}";

		break;

	case "eraserooms":

		$roomJson = file_get_contents('php://input');
		$rooms = json_decode($roomJson);

		// Here you would delete the rooms from the database...

		// Returning success for demo purposes.
		$result = "{'success':true}";

		break;

}

header('Cache-Control: no-cache, must-revalidate');
header("content-type:application/json");
echo($result);

Now you can check out the behaviors that the related models have. In the app.js file, you can try the following code:

Ext.application({
    name: 'App',
    models: ['Room', 'Hotel'],
    launch: function () {

        var myHotel = Ext.create('App.model.Hotel', {
            id: 1,
            name: 'Siesta by the Ocean',
            address: '1 Ocean Front, Happy Island',
            status: 1
        });

        var rooms = myHotel.rooms();

        rooms.each(function (item, index, length) {
            console.log('Room Id: ' + item.id + ', room type: ' + item.type);
        });

        rooms.load(); // Should see request with: act:loadrooms, page: 1, start: 0, limit: 25, filter: [{ "property": "hotelId", "value": 1}]

    }
});

Using Google Chrome, you can browse to the index.html file, open the developer tools and inspect the request to the rooms.php file. The console’s output should look similar to this:

The query string parameters clearly show a filter property that contains the id of the hotel the rooms belong to. This is one of the behaviors that the hasMany association provides for us.

How It Works

As you can see in the code, you can obtain the rooms associated with a hotel by invoking the rooms() method of the Hotel model, which returns an instance of a data store. The method is automatically created based on the hasMany config:

hasMany: {
    model: 'App.model.Room',
    name:'rooms'
}

In the app.js file, you will now add a couple of rooms to the current hotel:

Ext.application({
    name: 'App',
    models: ['Room', 'Hotel'],
    launch: function () {

        var myHotel = Ext.create('App.model.Hotel', {
            id: 1,
            name: 'Siesta by the Ocean',
            address: '1 Ocean Front, Happy Island',
            status: 1
        });

        var rooms = myHotel.rooms();

        rooms.each(function (item, index, length) {
            console.log('Room Id: ' + item.id + ', room type: ' + item.type);
        });

        rooms.load(); // Should see request with: act:loadrooms, page: 1, start: 0, limit: 25, filter: [{ "property": "hotelId", "value": 1}]

        var room1 = Ext.create('App.model.Room', {
            id: 1,
            standardRate: 5,
            floor: 3,
            type: 'Royal Suite',
            status: 1,
            smoking: false
        });

        var room2 = Ext.create('App.model.Room', {
            id: 2,
            standardRate: 2,
            floor: 1,
            type: 'Single',
            status: 1,
            smoking: false
        });

        rooms.add(room1);
        rooms.add(room2);

        rooms.sync(); // Rooms have the hotelId property populated.
    }
});

The call to rooms.sync() will upload the rooms to the server. Chrome’s console should reflect the operation:

The hotelId field of these rooms is set to 1, which is the id of their parent hotel. Note that you did not have to take care of this. It happens automatically thanks to the hasMany association you defined.

Want To Learn More?

My Sencha Touch books will teach you how to create a Sencha Touch application, step by step, from mockups to production build.

  • Sencha Touch 2 Book
  • Sencha Touch 1 Book

Stay Tuned

Don’t miss any articles. Get free updates in your inbox.



MiamiCoder will never sell your email address.

Tagged With: Sencha Touch Tutorial 12 Comments

Comments

  1. JB says

    September 20, 2012 at 9:21 AM

    Hi,
    Why when we do a room.add , the “updateroom” parameter is passed to the url !? Why not the “createroom” parameter ?
    Tks !

    JB

    Reply
    • Jorge says

      September 21, 2012 at 5:09 PM

      That’s because I have already assigned an id to each model instance. The store interprets as new the records which do not have an id yet (phantom) and are also valid. If you remove the id config from the call to Ext.create, you will see act:createrooms in the request.

      Reply
  2. edie says

    September 27, 2012 at 11:51 AM

    Hi Jorge,

    thanks for the very nice article, but how if I create a ‘native like app’ using hasMany association on it’s model? what should I write as the value of the create, read, update and destroy property? is it depending to the type of proxy?

    thanks,
    edie

    Reply
    • Jorge says

      September 27, 2012 at 8:48 PM

      The proxy essentially defines where the data is saved. You can use server-side or client-side proxies. Not sure what you mean by ‘native like app’.

      Reply
  3. geetha says

    March 18, 2013 at 12:27 PM

    Hi Jorge,
    Thank you for ST2 Book. I’ve recently downloaded this book and the examples are very descriptive. They are of great use.
    I was just wondering, if you have an example of hasMany associations using MVC with ST2.1.1. I’m trying to implement a simple example, but this seems to be a nightmare for me.
    Example: I have a json response with Orders with Items in it. I could able to get the Orders as list but then on the detail view I would like to display the items.
    {
    “orders”: [
    {
    “id”: “1”,
    “poNr”: “A123”
    “order_items”: [
    {
    “id”: 10,
    “total”: 10.76,
    “status”: “invoiced”
    },
    {
    “id”: 11,
    “total”: 13.45,
    “status”: “shipped”
    }
    ]
    },
    ]
    }

    Regards,
    Geetha

    Reply
    • Jorge says

      March 18, 2013 at 9:43 PM

      Thank you Geetha. I know the hasMany association usage is confusing. I will post an example as soon as possible.

      Reply
      • john says

        July 10, 2013 at 3:55 PM

        what if u want to post the Hotel.rooms hierarchy starting at the root of hotel. I tried the following , I have multiple settings per machine but same idea as rooms per hotel. this produced a JSON stream that did not include the settings

        var machinesStore = Ext.getStore(‘machines’);
        var machine = Ext.create(‘MyApp.model.machine’, {
        machineid: “”,
        Name: ‘my first machine’,
        PictureUrl: ‘test.jpg’
        });

        var settings = machine.attributes(); //this is a store
        var setting1 = Ext.create(‘MyApp.model.machinesetting’, {
        Name: ‘setting1’

        });
        var setting2 = Ext.create(‘MyApp.model.machinesetting’, {
        Name: ‘setting2’

        });
        settings.add( setting1);
        settings.add(setting2);
        machinesStore.add(machine);
        debugger;
        machinesStore.sync();

        if I run in Chrome to the breakpoint and look at the machineStore I see the Name and PictureUrl set and in the Settings store I see the setting name set. What am I missing

        Reply
        • Jorge says

          July 10, 2013 at 5:31 PM

          John, please send me your code through email.

          Reply
          • Rajarshi says

            September 3, 2015 at 4:31 AM

            Hi Jorge.
            Could you please post or email me the solution to John’s problem?
            I need the code to add and sync the parent record wherein the framework will save all associated(has many) records too.
            Thank you.

  4. Sur007 says

    July 11, 2013 at 8:55 AM

    hello,
    can you please help me on this issue
    stackoverflow.com/questions/17590305/cannot-parse-nested-json-fully-sencha

    Reply
    • Jorge says

      July 11, 2013 at 9:07 AM

      Sur007, send me the code through email.

      Reply
  5. Sur007 says

    July 12, 2013 at 2:24 AM

    I have send it sir. Please have a look onto it.

    Reply

Leave a Comment Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Get My Books

The beginner's guide to Sencha Touch apps
The beginner's guide to jQuery Mobile apps

Book: How to Build a jQuery Mobile Application

Topics

  • » jQuery Mobile Tutorials
  • » Sencha Touch Tutorials
  • » ExtJS Tutorials
  • » Books
  • » Tools
  • » .Net Tutorials
  • » BlackBerry Tutorials
  • » iOS Tutorials
  • » Node.js Tutorials
  • » Android Training
  • » BlackBerry Training
  • » iOS Training

Search

Contact Me

  •  Email: jorge[AT]jorgeramon.me
  •  Twitter: @MiamiCoder
  •  LinkedIn: Jorge Ramon


Don’t Miss the Free Updates

Receive free updates in your inbox.
Your address is safe with me.

Copyright © 2021 Jorge Ramon · The opinions expressed herein do not represent the views of my employers in any way · Log in