PDA

View Full Version : Problems with REST crud



kesteb
5 Nov 2009, 3:40 PM
First some code so we are on the same page:




Ext.namespace('App', 'App.view', 'App.model');

App.model.Notifications = function() {

var proxy = new Ext.data.HttpProxy({
api: {
create: {
utl: '/events/alerts/create',
method: 'POST'
},
destroy: {
url: '/events/alerts/delete',
method: 'POST'
},
read: {
url: '/events/alerts',
method: 'GET'
},
update: {
url: '/events/alerts/update',
method: 'POST'
}
}
});

var datastore = new Ext.data.GroupingStore({
proxy: proxy,
reader: new Ext.data.JsonReader({
root: 'data',
idProperty: 'id',
totalProperty: 'count',
successProperty: 'success',
fields: [
{name: 'id', type: 'int'},
{name: 'hostname', type: 'string'},
{name: 'datetime', type: 'string'},
{name: 'priority', type: 'string'},
{name: 'facility', type: 'string'},
{name: 'message', type: 'string'}
]
}),
writer: new Ext.data.JsonWriter(),
groupField: 'priority',
remoteSort: true,
sortInfo: {
field: 'datetime',
direction: 'ASC'
},
restful: true
});

return datastore;

};



If you will notice, I have defined the API parameter to use POST for create/destory/update. Ext rather blithly ignores this and sends DELETE,PUT,POST instead. Not a big problem because I am not checking the method used in the backend. It is the url that has the meaning not the method. But it is not a warm fuzzy when parameters are ignored.

Now for some application code:




App.view.GridPanel = Ext.extend(Ext.grid.GridPanel, {

id: 'grid-panel',
title: 'Grid Panel',
loadMask: true,

initComponent: function() {

var paging_tool_bar = new Ext.PagingToolbar({
pageSize: this.page_limit,
displayInfo: true,
displayMsg: 'Total {2} results found. Currently showing {0} - {1}',
emptyMsg: 'No results to display',
store: this.datastore
});

Ext.apply(this, {
id: this.id,
title: this.title,
border: false,
viewConfig: {
forceFit: true
},
enableColLock: false,
ds: this.datastore,
cm: this.column_model,
sm: new Ext.grid.RowSelectionModel({singleSelect: true}),
view: new Ext.grid.GroupingView(),
bbar: paging_tool_bar,
plugins: [this.grid_filter]
});

paging_tool_bar.on({
beforechange: {
fn: function(ptb, options) {
this.page_limit = options.limit;
this.page_start = options.start;
},
scope: this
}
});

App.view.GridPanel.superclass.initComponent.apply(this, arguments);

}

});

App.view.AlertsPanel = Ext.extend(App.view.GridPanel, {

id: 'alerts-panel',
title: 'Alerts',
page_start: 0,
page_limit: 15,
column_model: null,
grid_filter: null,
datastore: null,
runner: null,
task: null,
firsttime: true,

constructor: function(config) {

config = config || {};
config.listeners = config.listerners || {};

Ext.applyIf(config.listeners, {
rowdblclick: {
fn: function(grid, index, e) {
this.cleared(grid, index);
},
scope: this
},
beforeclose: {
fn: function() {
this.runner.stop(this.task);
},
scope: this
}
});

App.view.AlertsPanel.superclass.constructor.apply(this, arguments);

},

initComponent: function() {

this.runner = new Ext.util.TaskRunner();
this.datastore = new App.model.Notifications();
this.column_model = new Ext.grid.ColumnModel({
columns: [
{
id: 'id',
header: 'ID',
dataIndex: 'id',
width: 50
},{
id: 'priority',
header: 'Priority',
dataIndex: 'priority',
width: 75
},{
id: 'facility',
header: 'Facility',
dataIndex: 'facility',
width: 75
},{
id: 'hostname',
header: 'Hostname',
dataIndex: 'hostname',
width: 100
},{
id: 'datetime',
header: 'Date',
dataIndex: 'datetime',
width: 135
},{
id: 'message',
header: 'Message',
dataIndex: 'message',
width: 427
}
],
defaults: {
sortable: true
}
});

this.grid_filter = new Ext.ux.grid.GridFilters({
filters: [
{
type: 'numeric',
dataIndex: 'id',
disabled: true
},{
type: 'string',
dataIndex: 'hostname'
},{
type: 'date',
dataIndex: 'datetime',
dateFormat: 'Y-m-d'
},{
type: 'list',
dataIndex: 'priority',
options: ['high', 'medium', 'low', 'info']
},{
type: 'list',
dataIndex: 'facility',
options: ['systems', 'dba']
}
]
});

this.task = {
run: function() {
this.dbload(this.datastore);
},
interval: 60000,
scope: this
};

this.datastore.on({
load: {
fn: function() {
if (this.firsttime) {
this.runner.start(this.task);
this.firsttime = false;
}
},
scope: this
},
write: {
fn: function(store, action, res, tld, rs) {
console.log('writer');
console.log(arguments);
},
scope: this
},
exception: {
fn: function(proxy, type, action, options, res) {
console.log('exception');
console.log(arguments);
switch (type) {
case 'response':
console.log('response');
title = 'Error';
text = res.statusText;
Ext.Msg.alert(title, text);
break;
case 'remote':
console.log('remote');
Ext.Msg.alert(
res.message.title,
res.message.text
);
break;
default:
Ext.Msg.alert('Error', 'An unknown error has happened');
}
},
scope: this
}
});

App.view.AlertsPanel.superclass.initComponent.apply(this, arguments);

},

onRender: function() {

this.dbload(this.store);

App.view.AlertsPanel.superclass.onRender.apply(this, arguments);

},

cleared: function(grid, index) {

var store = grid.getStore();

Ext.Msg.confirm(
'Message',
'Do you really want to clear event?',
function(btn) {
if (btn == 'yes') {

store.removeAt(index);
store.save();

}

}
);

},

dbload: function(store) {

store.load({
params: {
start: this.page_start,
limit: this.page_limit
}
});

}

});

Ext.reg('view_alerts_panel', App.view.AlertsPanel);

Ext.onReady(function() {

var view_port = new Ext.Viewport({
layout: 'border',
plain: true,
defaults: {
split: true,
animFloat: false,
autoHide: false,
useSplitTips: true
},
items: [
{
region: 'north',
xtype: 'view_header_panel'
},{
region: 'center',
xtype: 'view_tab_panel',
items: [{
xtype: 'view_alerts_panel',
loadMask: false,
closable: true
},{
xtype: 'view_process_panel',
loadMask: false,
closable: true
}],
activeTab: 0
},{
xtype: 'view_menu_panel',
url: '/perfs/menu',
treeText: 'testing',
treeId: 'testing',
title: 'Navigation',
region: 'west'
}
]
});

view_port.show();

});



OK, what does this do. It displays a menu panel in "west" and a tab panel in "center" with two panes. The "Alerts" pane allows you to double click on a row. At which point a message box pops up to confirm the action. Clicking "OK" sends a delete request to the backend. The backend performs the operation and send back a 200 status code and this chunk of JSON:




{
"success": true,
"message": {
"title": "Deleted",
"text": "You succesfully deleted x"
}
}



Which is promply thrown into the exception handler with a type of "response". Not exactly what is wanted and the actual response is lost when this happens. The statusText is "communications failure".

This is not the desired behavior, what is wanted is for a nice dialog box to pop up and display the success message. The question is how to do that?

kesteb
13 Nov 2009, 3:19 PM
Any ideas? This code works fine in Firefox but fails in IE.

abraxxa
18 Nov 2009, 8:34 AM
You're doing RPC, not REST if the url is different.
REST would be an url pointing to the object e.g. /alert/35 and using the http methods to decide what to do.

vitolini
12 Jan 2011, 3:23 PM
I am having a similar problem, did you get this solved?

Thanks