]> git.proxmox.com Git - extjs.git/blame - extjs/packages/core/src/data/writer/Json.js
add extjs 6.0.1 sources
[extjs.git] / extjs / packages / core / src / data / writer / Json.js
CommitLineData
6527f429
DM
1/**\r
2 * This class is used to write {@link Ext.data.Model} data to the server in a JSON format.\r
3 * The {@link #allowSingle} configuration can be set to false to force the records to always\r
4 * be encoded in an array, even if there is only a single record being sent.\r
5 */\r
6Ext.define('Ext.data.writer.Json', {\r
7 extend: 'Ext.data.writer.Writer',\r
8 alternateClassName: 'Ext.data.JsonWriter',\r
9 alias: 'writer.json',\r
10 \r
11 config: {\r
12 /**\r
13 * @cfg {String} rootProperty The HTTP parameter name by which JSON encoded records will be passed to the server if the\r
14 * {@link #encode} option is `true`.\r
15 */\r
16 rootProperty: undefined,\r
17 \r
18 /**\r
19 * @cfg {Boolean} [encode=false] Configure `true` to send record data (all record fields if {@link #writeAllFields} is `true`)\r
20 * as a JSON encoded HTTP parameter named by the {@link #rootProperty} configuration.\r
21 * \r
22 * The encode option should only be set to true when a {@link #rootProperty} is defined, because the values will be\r
23 * sent as part of the request parameters as opposed to a raw post. The root will be the name of the parameter\r
24 * sent to the server.\r
25 */\r
26 encode: false,\r
27 \r
28 /**\r
29 * @cfg {Boolean} [allowSingle=true] Configure with `false` to ensure that records are always wrapped in an array, even if there is only\r
30 * one record being sent. When there is more than one record, they will always be encoded into an array.\r
31 */\r
32 allowSingle: true,\r
33 \r
34 /**\r
35 * @cfg {Boolean} [expandData=false] By default, when dot-delimited field {@link #nameProperty mappings} are\r
36 * used (e.g. `name: 'myProperty', mapping: 'my.nested.property'`) the writer will simply output a flat data\r
37 * object containing the mapping string literal as the property name (e.g. `{ 'my.nested.property': 'foo' }`).\r
38 * \r
39 * Mappings are used to map incoming nested JSON to flat Ext models. In many case, the data output by the\r
40 * writer should preferrably match the original nested data format. Setting this config to `true` will ensure\r
41 * that the output will instead look like `{ my: { nested: { property: 'foo' }}}`. The output is generated\r
42 * by {@link #getExpandedData}, which can optionally be overridden to apply more customized logic.\r
43 */\r
44 expandData: false\r
45 },\r
46 \r
47 //<debug>\r
48 constructor: function(config) {\r
49 if (config && config.hasOwnProperty('root')) {\r
50 config = Ext.apply({}, config);\r
51 config.rootProperty = config.root;\r
52 delete config.root;\r
53 Ext.log.warn('Ext.data.writer.Json: Using the deprecated "root" configuration. Use "rootProperty" instead.');\r
54 }\r
55 this.callParent([config]);\r
56 },\r
57 //</debug>\r
58 \r
59 /**\r
60 * @protected\r
61 * The Reader classes support dot-delimited data mappings for extracting nested raw data into fields, so the\r
62 * writer must support converting the flat {@link Ext.data.Model} structure back into the original nested data\r
63 * format. Using the same mappings when available, the Writer will simply split each delimiter into a nested\r
64 * object in the output, which should exactly match the input format. For example, record data like this:\r
65 * \r
66 * my.nested.property: 'foo',\r
67 * my.nested.another: 'bar',\r
68 * my.somethingElse: 123\r
69 * \r
70 * should write out as...\r
71 * \r
72 * my: {\r
73 * nested: {\r
74 * property: 'foo',\r
75 * another: 'bar\r
76 * },\r
77 * somethingElse: 123\r
78 * }\r
79 *\r
80 * This behavior is governed by the {@link #expandData} config. By default, this option is `false` for\r
81 * compatibility reasons, and will output a flat structure matching the flat record format. Setting this config\r
82 * to `true` will enable the expanded mapping behavior as shown here. This method could also be overridden\r
83 * to provide an even more customized output data structure.\r
84 */\r
85 getExpandedData: function(data) {\r
86 var dataLength = data.length,\r
87 i = 0,\r
88 item,\r
89 prop,\r
90 nameParts,\r
91 j,\r
92 tempObj,\r
93 \r
94 toObject = function(name, value) {\r
95 var o = {};\r
96 o[name] = value;\r
97 return o;\r
98 };\r
99 \r
100 for (; i < dataLength; i++) {\r
101 item = data[i];\r
102 \r
103 for (prop in item) {\r
104 if (item.hasOwnProperty(prop)) {\r
105 // e.g. my.nested.property: 'foo'\r
106 nameParts = prop.split('.');\r
107 j = nameParts.length - 1;\r
108 \r
109 if (j > 0) {\r
110 // Initially this will be the value 'foo'.\r
111 // Equivalent to rec['my.nested.property']\r
112 tempObj = item[prop];\r
113 \r
114 for (; j > 0; j--) {\r
115 // Starting with the value above, we loop inside out, assigning the\r
116 // current object as the value for the parent name. Work all\r
117 // the way up until only the root name is left to assign.\r
118 tempObj = toObject(nameParts[j], tempObj);\r
119 }\r
120 \r
121 // At this point we'll have all child properties rolled up into a single\r
122 // object like `{ nested: { property: 'foo' }}`. Now add the root name\r
123 // (e.g. 'my') to the record data if needed (do not overwrite existing):\r
124 item[nameParts[0]] = item[nameParts[0]] || {};\r
125 // Since there could be duplicate names at any level of the nesting be sure\r
126 // to merge rather than assign when setting the object as the value:\r
127 Ext.Object.merge(item[nameParts[0]], tempObj);\r
128 // Finally delete the original mapped property from the record\r
129 delete item[prop];\r
130 }\r
131 }\r
132 }\r
133 }\r
134 return data;\r
135 },\r
136 \r
137 writeRecords: function(request, data) {\r
138 var me = this,\r
139 root = me.getRootProperty(),\r
140 json, single, transform;\r
141 \r
142 if (me.getExpandData()) {\r
143 data = me.getExpandedData(data);\r
144 }\r
145 \r
146 if (me.getAllowSingle() && data.length === 1) {\r
147 // convert to single object format\r
148 data = data[0];\r
149 single = true;\r
150 }\r
151 \r
152 transform = this.getTransform();\r
153 if (transform) {\r
154 data = transform(data, request);\r
155 }\r
156 \r
157 if (me.getEncode()) {\r
158 if (root) {\r
159 // sending as a param, need to encode\r
160 request.setParam(root, Ext.encode(data));\r
161 } else {\r
162 //<debug>\r
163 Ext.raise('Must specify a root when using encode');\r
164 //</debug>\r
165 }\r
166 } else if (single || (data && data.length)) {\r
167 // send as jsonData\r
168 json = request.getJsonData() || {};\r
169 if (root) {\r
170 json[root] = data;\r
171 } else {\r
172 json = data;\r
173 }\r
174 request.setJsonData(json);\r
175 }\r
176 return request;\r
177 }\r
178});\r