HTTP DELETE request without body - javascript

I am facing the same problem as mentioned here: I am trying to connect my ExtJS 4.1 store with REST API, but when I delete the record from the store and consequently invoke HTTP DELETE method, it gets rejected by the server-side because the HTTP request that ExtJS sent contains body. Unfortunately, the accepted answer on the link above is not valid for version 4 of ExtJS and higher.
The best that I achieved so far is to send empty array (literally, [] ) as a body, but of course this is still rejected:
This is my code:
Ext.define('TT.proxy.CustomRestProxy', {
alias: 'proxy.customrestproxy',
extend: 'Ext.data.proxy.Rest',
buildRequest: function(operation) {
var request = this.callParent(arguments);
if(operation.action === 'destroy')
{
delete request.operation.records;
}
return request;
}
});
defineStore = function(storeName, modelName, url) {
var storeProperties = {
extend: 'Ext.data.Store',
requires: modelName,
model: modelName,
id: storeName,
proxy: {
type: 'customrestproxy',
url: url,
batchActions: false,
noCache: false,
headers: { 'Content-Type': 'application/json' },
reader: {
type : 'json',
totalProperty: 'total',
successProperty: 'success',
root: 'data'
},
writer: {
type : 'json'
},
}
};
Ext.define(storeName, storeProperties);
};
I would accept any answer that solves this issue, it does not have to include ExtJS-specific features, i.e. intercepting AJAX request or similar technique is also welcome.

There is a workaround based on AJAX interceptor, inspired by this link. This code solves the problem regardless of the framework used, so it can be also useful for other people who are not necessarily using Ext JS:
(function(XHR) {
"use strict";
var open = XHR.prototype.open;
var send = XHR.prototype.send;
var httpMethod;
XHR.prototype.open = function(method, url, async, user, pass) {
httpMethod = method;
this._url = url;
open.call(this, method, url, async, user, pass);
};
XHR.prototype.send = function(data) {
if(httpMethod === 'DELETE')
{
data = null;
}
send.call(this, data);
}
})(XMLHttpRequest);

Related

ExtJS GET action to store returns 500 in FireFox

I'm getting the strangest behavior from FireFox when loading data from a Web API GET request whereas other browsers do this perfectly. Here is what Fiddler can tell me when I use Firefox:
3817 500 HTTP localhost:52543 /api/Tasks/Get?_dc=1442848131483&page=1&start=0&limit=25 5 403 private application/xml; charset=utf-8 firefox:138020
Same action, other browser (Chrome):
3954 200 HTTP localhost:52543 /api/Tasks/Get?_dc=1442848159073&page=1&start=0&limit=25 1 508 no-cache; Expires: -1 application/json; charset=utf-8 chrome:2808
I'm unable to catch the error in the Application_Error, nor do I receive errors in the exception listener on the client-side, so I suspect something is going wrong between returning the result to the client and the client processing the results, but I have no clue at all where the problem might be situated.
Here is the store definition:
Ext.define('SchedulerApp.store.UnplannedTaskStore', {
extend: 'Ext.data.Store',
model: 'UnplannedTask',
autosync: false,
autoLoad: true,
proxy: {
type: 'rest',
api: {
read: '/api/Tasks/Get',
add: '/api/Tasks/Add',
update: '/api/Tasks/Update',
destroy: '/api/Tasks/Destroy'
},
actionMethods: {
create: 'POST',
read: 'GET',
update: 'POST',
destroy: 'POST'
},
reader: {
type: 'json',
rootProperty: 'data',
totalProperty: 'total'
},
writer: {
type: 'json',
writeAllFields: true
}
},
listeners: {
load: function (sender, node, records) {
},
exception: function (proxy, response, options) {
Ext.MessageBox.alert('Error', response.status + ": " + response.statusText);
}
}
});
and the model:
Ext.define('UnplannedTask', {
extend: 'Ext.data.Model',
fields: [
{ name: 'Importance', type: 'float' },
{ name: 'Category', type: 'string' },
{ name: 'TaskNo', type: 'float' }
]
});
This is what I have in the Web API:
[System.Web.Http.HttpGet]
public async Task<dynamic> Get(string page, string start, string limit)
{
// Get items from database with request information from the Kendo Grid Control
PagingResult<TaskViewModel> tasks = await this.Worker.GetPagedTasksAsync(int.Parse(page), int.Parse(limit), null, null);
// Map them to store objects
var convertedTasks = new SchedulerTasksViewModel()
{
total = tasks.Count,
data = tasks.Items.Select(x => new SchedulerTask()
{
Importance = x.Importance,
Category = x.Category,
TaskNo = x.TaskNumber
}).ToArray()
};
var response = Request.CreateResponse(HttpStatusCode.OK, convertedTasks);
return response;
}
Could it be a browser issue or am I missing something on the server side?
Try adding this header to your proxy:
headers: {'Content-Type': "application/json" }
I would like to elaborate a bit. The error is thrown by the XML serializer; you don't see the details because IIS does not send them to the front.
I would recommend to modify all your API calls such that they work with XML as well - even if your front-end does not use XML. It's far easier to debug if you can just open API calls in new browser tabs and the XML serializer does not mask code errors with serialization errors.
To see the error message, you would have to allow your development IIS to bring errors to the front:
Open the IIS7 manager
Select the Website and on its features view, double click on “Error Pages”.
Right click and select the “Edit Feature Settings…” or select the same from the Actions pane (in the right hand side)
Select the “Detailed errors” radio button and click on OK
(Source)
My best guess is that you just have to decorate some types or properties with [DataContract], [DataContractAttribute] or [DataMemberAttribute]. The error message will tell you which ones and how to decorate.
Another thing entirely: If you use more than one Ajax request, I'd recommend to define an override on the Ajax proxy. That way you can't forget one:
Ext.define("MyApp.override.Ajax", {
override:'Ext.data.proxy.Ajax',
headers:{'Accept':'application/json'}
});

Access the Google api using Extjs 4.2

I have tried to access the following url using Extjs sencha. Data not loaded on run time. When i try to access the url on browser i am able to see the data
https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=true&key=API_KEY.
I am newbie for Extjs.I know i am trying to load the cross domain data.But i dont know how to achieve this. Please somebody help me
Ext.define('MyApp.store.MyJsonStore', {
extend: 'Ext.data.Store',
requires: [
'MyApp.model.MyModel',
'Ext.data.proxy.Ajax',
'Ext.data.reader.Json'
],
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
model: 'MyApp.model.MyModel',
storeId: 'MyJsonStore',
proxy: {
type: 'ajax',
url: 'https://maps.googleapis.com/maps/api/geocode/json?address=Barcroft + Plaza +Apartments ,+22041&sensor=true&key=API_KEY',
reader: {
type: 'json'
}
},
listeners: {
load: {
fn: me.onJsonstoreLoad,
scope: me
}
}
}, cfg)]);
},
onJsonstoreLoad: function(store, records, successful, eOpts) {
Ext.MessageBox.show('Loaded');
}
});
Instead of Ajax proxy i have tried jsonp also.If i use jsonp then i am getting uncaught syntaxerror unexpected token .I have searched so many blogs, forums everybody talked about adding callback but i am calling third party api
I have tried following code for jsonp.I Have tried both ways like with and without callback key
proxy: {
type: 'jsonp',
url: 'https://maps.googleapis.com/maps/api/geocode/json?address=1600+Amphitheatre+Parkway,+Mountain+View,+CA&sensor=true&key=API_KEY',
callbackKey: 'Mycallback',
reader: {
type: 'json',
root: 'results'
}

ExtJS store initialization using json fails

I have a store like this:
Ext.define('app.store.System', {
extend : 'Ext.data.Store',
model : 'app.model.System',
autoLoad: true,
autoSync: true,
proxy: {
type: 'rest',
format: 'json',
url: '/application/appinfo',
method : "GET",
reader: {
type: 'json',
root: 'System'
},
writer: {
root: 'System',
allowSingle: false
}
}
});
and I have a service endpoint to handle requests that match /application with this method:
#GET
#Path("/{sysinfo}")
public List<SystemInfo> getSystemInfo() {
if(sysinfo == null){
sysinfo = new SystemInfo();
...initialize
}
List<SystemInfo> resultList = new ArrayList<SystemInfo>();
resultList.add(sysinfo);
return resultList;
}
and it seemed to work... when I tried to to reach localhost:port/application/sysinfo.json I got this:
{ [{"address":"...","feeds":["feed1","feed2"] } ] }
which seems correct but when I try to read the data from the store in the view's init method:
var store = Ext.StoreManager.lookup('System');
var data = [];
store.each(function(record) {
data.push(record.getData());
console.log("record data: ");
console.log(record.getData());
});
console.log(data[0]);
It says that it's undefined as if the store was empty. I tried it with the debugger and i found that the getSystemInfo() was called after the view's initcomponent but unfortunately I don't know why that is or how to solve it. Any ideas?
Thanks for your time.
Have you tried loading your store first?
var store = Ext.StoreManager.lookup('System');
var data = [];
store.load({
callback: function(storeVar, records, successful) {
Ext.each(records, function(record) {
data.push(record.getData());
console.log("record data: ");
console.log(record.getData());
});
}
console.log(data[0]);
});
And what boris says is true, you need to define your root property in the returned JSON.
If you're using chrome or firefox you can also check which network call is made, and what it returns (JSON data...).
Try this:
return new { success: true, System = resultList};

EXT JS Store's Proxy: readers and writers

In the documentation, i have found a store instantiated like this:
var store = Ext.create('Ext.data.Store', {
autoLoad: true,
model: "User",
proxy: {
type: 'ajax',
url : 'users.json',
reader: {
type: 'json',
root: 'users'
}
}
});
The proxy has one url config. I am particularly interested in the reader. The reader specifies the data exchange format (json) and the root ('users'). Now, in other words if the store is set up to be: autoLoad = true, then EXT JS will make an Ajax connection to the url specified in order to read. Now, how would i configure a writer for that same store above? Someone also tell me about this: if i configure a writer, would it use the same url as specified in the proxy? am still confused about writers and readers in context of the code i have showed above, you would help me use the above example to show readers and writer configs. Thank you.
Here is an example of a store with reader, writer and api in my App:
Ext.define('MyApp.store.Tasks', {
extend: 'Ext.data.Store',
model: 'MyApp.model.Task',
sorters : [{
property: 'idx',
direction: 'ASC'
}],
autoSync:true,
proxy:{
type: 'ajax',
reader: {
type: 'json',
root: 'data'
},
writer: {
type: 'json',
writeAllFields : false, //just send changed fields
allowSingle :false //always wrap in an array
// nameProperty: 'mapping'
},
api: {
// read:
create: 'task/bulkCreate.json',
update: 'task/bulkUpdate.json'
// destroy:
}
},
listeners : {
write: function(store, operation, opts){
console.log('wrote!');
//workaround to sync up store records with just completed operation
Ext.each(operation.records, function(record){
if (record.dirty) {
record.commit();
}
});
},
update:function(){
console.log('tasks store updated');
}
}
});
Actually you are correct - it will use the same url as for reader.
Proxy is a mediator between your model/store on a client and your server code on another side.
Readers are used for reading data and you could configure stuff like formatting, specify root etc. Writers are in charge of save/update requests to the server.
Check this article: http://edspencer.net/2011/02/proxies-extjs-4.html

wijdatasource error

Is there a way to debug or get an error when wijdatasource complete is request with a wijhttpproxy and have some problems with the data?
data: new wijdatasource({
dynamic: true,
proxy: new wijhttpproxy({
url: "#Url.Action("List")",
type: "POST",
dataType: "json"
}),
reader: {
read: function (datasource) {
alert(datasource);
var count = datasource.data.TotalRowCount;
datasource.data = datasource.data.Items;
datasource.data.totalRows = count;
new wijarrayreader([
{ name: "CdCF", mapping: "CdCF" },
{ name: "Descrizione", mapping: "Descrizione" }
]).read(datasource);
}
}
})
With the internet explorer debugger I can see the call is made with a 200 HTTP response to the List action but "alert(datasource);" is never executed.
I want to get the error that make the datasource not parse the data (if this is the error).
In a standard ajax call I could have had an "error" callback to try to debug the problem.
$.ajax({
error: function (error) {
alert("error: " + error);
},
url: '#Url.Action("List")',
success: function (code) {
var myModel = {
items: eval(code)
};
}
});
I think you want to do a Get instead of a Post.
proxy: new wijhttpproxy({
url: "#Url.Action("List")",
type: "Get",
dataType: "json"
}),
What I did is that I caught the error in the controller an modified the object I was sending back to have a "success" boolean that I checked on the read function so that if datasource.data.success was true, then I would process the data if not I would spit out a message. You would have to put everything in your controller action inside a try-catch block.

Categories