]>
Commit | Line | Data |
---|---|---|
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 | |
6 | Ext.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 |