Sep 03, 2014, 10:53 AM
[CLOSED] Getting raw JSON data in MVC Controller Post
Hi,
This follows on from this thread:
http://forums.ext.net/showthread.php?42721
That previous thread was about extending the TreeStore class to support rejectChanges() and commitChanges(), to allow the use of an AjaxProxy in a more elegant way. It also used a custom JsonWriter so that I could control the amount of data that gets sent back to the server when committing some changes (in my particular case, delete of tree nodes).
A follow up from that is a variation of the example use in that post. I switched from pointing my Destroy API to an ASHX to point to an MVC Controller instead. However, I was struggling to find the best way to get both the raw data and the ExtraParameters to come through. In the end I had to settle for the solution I mention below, so this post is asking if there is a cleaner way I missed out?
ASPX example code [same as previous thread but with a different Destroy API URL]:
Thanks!
This follows on from this thread:
http://forums.ext.net/showthread.php?42721
That previous thread was about extending the TreeStore class to support rejectChanges() and commitChanges(), to allow the use of an AjaxProxy in a more elegant way. It also used a custom JsonWriter so that I could control the amount of data that gets sent back to the server when committing some changes (in my particular case, delete of tree nodes).
A follow up from that is a variation of the example use in that post. I switched from pointing my Destroy API to an ASHX to point to an MVC Controller instead. However, I was struggling to find the best way to get both the raw data and the ExtraParameters to come through. In the end I had to settle for the solution I mention below, so this post is asking if there is a cleaner way I missed out?
ASPX example code [same as previous thread but with a different Destroy API URL]:
<%@ Page Language="C#" %>
<%@ Register TagPrefix="cc1" Namespace="Ext.Net2.Tests.Trees.CustomWriter" Assembly="Ext.Net2.Tests" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>Title</title>
<ext:ResourcePlaceHolder Mode="ScriptFiles" />
<script>
// See http://forums.ext.net/showthread.php?42721 for reasons to extend/override some of these classes
// #####################################################################
// Custom Writer for category to control what data is sent to the server
// #####################################################################
Ext.define('Ext.ux.CategoryNodeWriter', {
extend: 'Ext.data.writer.Json',
alias: 'writer.categorynodewriter',
getRecordData: function(record, operation) {
console.log("getRecordData", record, record.getOwnerTree());
return operation.action === 'destroy' ? { 'id': record.get('id') } : this.callParent(arguments);
}
});
/**
* @author Johan Vandeplas
*/
Ext.define('My.overrides.data.NodeInterface', {
override: 'Ext.data.NodeInterface',
statics: {
getPrototypeBody: function () {
var me = this,
protBody = me.callParent(arguments),
removeFn = protBody.remove;
protBody.remove = function () {
var me = this;
me.removedFromNode = me.parentNode;
me.removedFromIdx = me.parentNode.indexOf(me);
removeFn.apply(this, arguments);
};
return protBody;
}
}
});
Ext.define('My.overrides.data.TreeStore', {
override: 'Ext.data.TreeStore',
/**
* removes node or an array of nodes from its parent.
* @param {Ext.data.NodeInterface/[Ext.data.NodeInterface]}nodes
* @param {Boolean} [destroy=false] True to destroy the node upon removal.
*/
remove: function (nodes, destroy) {
nodes = Ext.isArray(nodes) ? nodes : [nodes];
Ext.each(nodes, function (node) {
node.remove(destroy === true);
});
},
/**
* @returns {Array}
*/
getRejectRecords: function () {
return Ext.Array.push(this.getNewRecords(), this.getUpdatedRecords(), this.getRemovedRecords());
},
/**
* brings the store to previous state (rejects all uncommitted changes)
*/
rejectChanges: function () {
var me = this,
recs = me.getRejectRecords(),
len = recs.length,
i = 0,
rec;
for (; i < len; i++) {
rec = recs[i];
rec.reject();
if (rec.phantom) {
me.remove(rec);
}
}
// Restore removed records back to their original positions
recs = me.removed;
len = recs.length;
for (i = len - 1; i >= 0; i--) {
rec = recs[i];
rec.removedFromNode.insertChild(rec.removedFromIdx, rec);
delete rec.removedFromNode;
delete rec.removedFromIdx;
rec.reject();
}
// Since removals are cached in a simple array we can simply reset it here.
// Adds and updates are managed in the data MixedCollection and should already be current.
me.removed.length = 0;
},
/**
* Commits all Records with {@link #getModifiedRecords outstanding changes}. To handle updates for changes,
* subscribe to the Store's {@link #event-update update event}, and perform updating when the third parameter is
* Ext.data.Record.COMMIT.
*/
commitChanges : function(){
var me = this,
recs = me.getModifiedRecords(),
len = recs.length,
i = 0;
for (; i < len; i++){
recs[i].commit();
}
// Since removals are cached in a simple array we can simply reset it here.
// Adds and updates are managed in the data MixedCollection and should already be current.
me.removed.length = 0;
},
});
</script>
</head>
<body>
<ext:ResourceManager runat="server" />
<ext:TreePanel ID="TreePanel1" runat="server" Width="300" Height="200">
<TopBar>
<ext:Toolbar runat="server">
<Items>
<ext:Button Text="Delete" Icon="Delete">
<Listeners>
<Click Handler="
var tree = #{TreePanel1},
node = tree.getSelectionModel().getSelection()[0];
if (!node) return;
node.remove();
tree.getStore().sync({
failure: function(batch) {
tree.getStore().rejectChanges();
},
success: function() {
tree.getStore().commitChanges();
}
});
" />
</Listeners>
</ext:Button>
</Items>
</ext:Toolbar>
</TopBar>
<Root>
<ext:Node Text="Tasks" Expanded="true">
<Children>
<ext:Node Icon="Folder" Text="Delete this 0" Leaf="true">
<CustomAttributes>
<ext:ConfigItem Name="id" Value="categoryNode0" Mode="Value" />
<ext:ConfigItem Name="task" Value="Project: Shopping" Mode="Value" />
<ext:ConfigItem Name="user" Value="Tommy Maintz" Mode="Value" />
</CustomAttributes>
</ext:Node>
<ext:Node Icon="Folder" Text="Delete this 1" Leaf="true">
<CustomAttributes>
<ext:ConfigItem Name="id" Value="categoryNode1" Mode="Value" />
<ext:ConfigItem Name="task" Value="Project: Shopping" Mode="Value" />
<ext:ConfigItem Name="user" Value="Tommy Maintz" Mode="Value" />
</CustomAttributes>
</ext:Node>
<ext:Node Icon="Folder" Text="Delete this 2" Leaf="true">
<CustomAttributes>
<ext:ConfigItem Name="id" Value="categoryNode2" Mode="Value" />
<ext:ConfigItem Name="task" Value="Project: Shopping" Mode="Value" />
<ext:ConfigItem Name="user" Value="Tommy Maintz" Mode="Value" />
</CustomAttributes>
</ext:Node>
</Children>
</ext:Node>
</Root>
<Store>
<ext:TreeStore runat="server" AutoSync="false" ShowWarningOnFailure="false">
<Model>
<ext:Model runat="server">
<Fields>
<ext:ModelField Name="task" />
<ext:ModelField Name="user" />
</Fields>
</ext:Model>
</Model>
<Proxy>
<ext:AjaxProxy Url="TreeLoader.ashx">
<API Destroy="~/Tree/Delete" />
<Writer>
<cc1:CustomWriter />
</Writer>
<ExtraParams>
<ext:Parameter Name="example" Value="1" Mode="Raw" />
</ExtraParams>
</ext:AjaxProxy>
</Proxy>
</ext:TreeStore>
</Store>
</ext:TreePanel>
</body>
</html>
Controller:public class TreeController : Controller
{
public ActionResult Delete(int example)
{
Request.InputStream.Seek(0, SeekOrigin.Begin);
string jsonData = new StreamReader(Request.InputStream).ReadToEnd();
// do stuff with jsonData
return this.Direct();
}
}
While the above works, is it the best way, or is there something cleaner? I tried using StoreDataHandler like this:public class TreeController : Controller
{
public ActionResult Delete(StoreDataHandler handler)
{
return this.Direct();
}
}
But, in the debugger, I could not see either the "example" extra parameter in the handler, nor could I extract the post data (the JsonData property was empty). Did I miss something in the setup of the proxy or something else to get StoreDataHandler to work, or am I unable to use it in this situation?Thanks!
Last edited by Daniil; Sep 04, 2014 at 3:05 PM.
Reason: [CLOSED]