26 Jun 2011

ExtJS 4: Proxy Calling ‘Create’ Instead of ‘Update’ When Saving Record

28 Comments Programming / Web Development

Recently, while working with a model and proxy in ExtJS 4, I ran into the issue where the model’s proxy would call the ‘create’ action instead of ‘update’ when saving changes to an existing record. Here’s the sample model and store we’ll be using to duplicate the problem:

Ext.Loader.setConfig({ // Set up auto-loading
    enabled: true,
    paths: {
        Ext: 'extjs/src'
    }
});
Ext.define('User', { // The store
    alias: 'widget.userModel',
    extend: 'Ext.data.Model',
    idProperty: 'id',
    fields: [{
        name: 'id',
        type: 'int'
    }, {
        name: 'name',
        type: 'string'
    }, {
        name: 'dob',
        type: 'date',
        dateFormat: 'Y-m-d'
    }],
    proxy: {
        type: 'ajax',
        api: {
            create: 'myBackend.php?action=create', // Called when saving new records
            read: 'data/users.json', // Called when reading existing records
            update: 'myBackend.php?action=update', // Called when updating existing records
            destroy: 'myBackend.php?action=destroy' // Called when deleting existing records
        },
        reader: {
            type: 'json', // We expect the server to give us a JSON string as a response
            root: 'users'
        }
    }
})

Ext.define('Users', {
    extend: 'Ext.data.Store',
    alias: 'widget.userStore',
    model: 'User',
    autoLoad: false,
    autoSync: true
});</pre>
This is a pretty straightforward example. We have a 'User' model with the following fields: id, name and dob (date of birth) and a store that is tied to that model. Let's load up one of those user objects from the database and try to change the title:
<pre escaped="true" lang="javascript" line="1">Ext.onReady(function() {
    Ext.widget('userModel').self.load(1, {
        success: function(record, operation) {
            record.data.name = 'Joe Smith';
        }
    })
})

Now let’s try saving our changes and take a peek at the AJAX request sent to the server (via Chrome’s JavaScript tools console):

Console Output:

record.save();
url: http://www.dev.levihackwith.com/dnd_dev/myBackend.php?action=create&amp;_dc=1309112727215
Query String Parameters:
action:create
...
1
As you can a see, our proxy attempted to create the record via the model proxy's 'create' api command instead of update it using the 'update' command. Why is this? Well, let's take a closer look at the record that was returned to us when we called the model's load method:

<a href="http://www.levihackwith.com/wp-content/uploads/2011/06/ScreenClip.png"><img class="size-full wp-image-72" title="Loaded User Model" src="http://www.levihackwith.com/wp-content/uploads/2011/06/ScreenClip.png" alt="User model returned when save() was called" width="513" height="204" /></a>

See the model's "phantom" property? That's been set to true. Let's learn a little more about this property via the API documentation (emphasis mine):
<blockquote>Phantom: Boolean
True when the record does not yet exist in the server-side database (see setDirty). <strong>Any record which has a real database pk [primary key] set as its id property is NOT a phantom</strong> -- it's real.</blockquote>
Now, what does that mean, exactly? Well, when you are setting up a model, one of the properties you can set is the idProperty property. This specifies which field in the model serves as the unique identifier for that record when it's sent and received from the server. Now let's take another look at the response from the server:

1
{
    'success': true,
    'users':[{
        'id': '',
        'name': 'John Smith',
        'dob': '1980-06-12'
    }]
}

See how the ID field is blank? Because it’s blank, Ext assumes that it’s not been saved to the database yet and sets the Phantom property to true. Once we adjust our backend code to set the value of the field that acts as the idProperty (in this case, “id”), Ext recognizes the record as coming from the server and sets Phantom to false:

So, next time your proxy starts misbehaving, double check your server responses and model configuration and make sure you’re returning a fully-populated object. Happy coding!

Tags: ,
written by
I’m a PHP/MySQL web developer with a heart of JavaScript and an eye for regular expressions. I believe that code can be as elegant as design can be beautiful and that the best part of programming is seeing people use what I’ve created.
Related Posts

28 Responses to “ExtJS 4: Proxy Calling ‘Create’ Instead of ‘Update’ When Saving Record”

  1. Reply Jeeshen Lee says:

    Thanks! Solve my problem.

  2. Reply John Sanders says:

    Thanks for this post. I’ve spent 2 days Googling, and a forum post at Sencha before I found your page. It’s the solution to my problem. I added the idProperty into my model and my REST proxy started working as expected.

  3. Reply denu says:

    Great post, thank you!
    Now I’ve run into trouble with my store is calling update instead of create when I add new node to a TreePanel. Can anyone suggest what can be reason of that?

  4. Reply Richard says:

    Thanks a lot.. You have saved the day !

  5. Reply ExtJs 4 proxy calls ‘Create’ instead of ‘Update’ | Dae’s blog says:

    [...] ExtJS 4: Proxy Calling ‘Create’ Instead of ‘Update’ When Saving Record. [...]

  6. Reply Dae says:

    Thank you so much for this post. I was trying to solve this riddle for a whole day. I think I would have never figured it out on my own — I wasn’t even using the idProperty in my script.

  7. Reply Felix says:

    Thank a lot! I was banging my head on the wall. It makes sense though, how is the update api going to work without an id to reference?

  8. Reply stelmo says:

    Thanks a lot, it really help a lot.

  9. Reply stephen says:

    terrific post. this helped me ferret out a nasty bug, and come to a deeper understanding of what’s going on behind the scenes with the proxy’s CRUD calls.
    thanks!

  10. Reply Ricardo says:

    Another thing: found about the ‘encode’ config option of Ext.data.writer.Json that puts the post data in the url. Thus you can access it in the backend with $_REQUEST, without the need for ‘raw data’ manipulation.

  11. Reply Ricardo says:

    Ok, solved this. Put proxy in store’s definition and then, on grid edit put ‘this.store.sync()’. Everything started to work. I updated the JSFiddle code. Go check it out!

  12. Reply Ricardo says:

    Oh, and thanks for the editing example, i will put it to good use!

  13. Reply Ricardo says:

    I need to return the completed model object along with the success message from the server’s JSON output, or else ‘record = operation.getRecords()[0];’ will trigger ‘Uncaught TypeError: Cannot read property ‘data’ of undefined’

  14. Reply Levi Hackwith says:

    I wasn’t able to spot anything that used operation.getRecords()[0]. I’d suggest checking out Sencha’s grid editing example. Maybe it’ll help. http://dev.sencha.com/deploy/ext-4.0.0/examples/grid/cell-editing.html

  15. Reply Ricardo says:

    link to updated JSFiddle

    http://jsfiddle.net/rikkman/fQEkW/

  16. Reply Ricardo says:

    Ok, now the problem is ‘Uncaught TypeError: Cannot read property ‘data’ of undefined’. Everything else is fine: save works but this ‘record = operation.getRecords()[0];’ remains undefined. :(

  17. Reply Ricardo says:

    There you go

    http://jsfiddle.net/rikkman/fQEkW/1/

    this code sends POST action create/update on grid edit, with request payload in raw data

  18. Reply Ricardo says:

    Will do, ’cause this thing is driving me loony! :) And i need all the help i can find

  19. Reply Ricardo says:

    Moved the proxy definition to model and now the issue is that i can only get the request payload on the php server side with the $GLOBALS['HTTP_RAW_POST_DATA']. Have to do some trickery to insert into mongodb…

    • Reply Levi Hackwith says:

      Ah! Yes! I need to write about the whole “raw data” issue sometime. You should post your code to JS Fiddle and post a link here so others can follow along with what you did. :)

  20. Reply Ricardo says:

    Ok, maybe the server error isnt the problem, because before that i get ‘Uncaught TypeError: Cannot call method ‘indexOf’ of undefined’ on saving from editing a grid ‘e.record.save();’

  21. Reply Ricardo says:

    URL: http://localhost/myApp/app/resources_crud.php?action=update&_dc=1309355122800
    Método: POST
    Estado: 500 Internal Server Error
    Duração: 220 ms

    Detalhes do pedido
    POST /myApp/app/resources_crud.php?action=update&_dc=1309355122800 HTTP/1.1
    User-Agent: Opera/9.80 (Windows NT 5.1; U; pt) Presto/2.9.168 Version/11.50
    Host: localhost
    Accept: text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
    Accept-Language: pt-PT,pt;q=0.9,en;q=0.8
    Accept-Encoding: gzip, deflate
    Referer: http://localhost/myApp/resources.php
    Connection: Keep-Alive
    Content-Length: 152
    Content-Type: application/json
    X-Requested-With: XMLHttpRequest
    Content-Transfer-Encoding: binary
    Detalhes da resposta
    HTTP/1.1 500 Internal Server Error
    Server: nginx/1.0.4
    Date: Wed, 29 Jun 2011 13:45:23 GMT
    Content-Type: text/html
    Connection: keep-alive
    X-Powered-By: PHP/5.3.6

  22. Reply Ricardo says:

    When i try this code my server complaints about POST method status 500 Internal Server Error. Maybe because the api update url is composed with ‘?action=update’, like a normal GET request?

    Thanks,
    Ricardo

    • Reply Levi Hackwith says:

      Hmmm. If you’re getting an internal server error, it’s most likely something with the backend code. The URL’s I used were completely made up and just for example. I’d check the AJAX response from the server and see what’s getting sent and received. If you’re still having trouble, please let me know. :)

  23. Reply Andrew Peacock says:

    By the way, it looks like you’ve not tagged this, as it doesn’t show up under the ‘extjs’ tag.
    Andy

  24. Reply Andrew Peacock says:

    Good post – thanks for sharing that. I’m only just beginning to move from ExtJS3 to 4, so it’s good to see some useful blog posts to make the path a little easier.

    Regards,
    Andy

Leave a Reply