OLD | NEW |
| (Empty) |
1 <!-- | |
2 Copyright (c) 2015 The Polymer Project Authors. All rights reserved. | |
3 This code may only be used under the BSD style license found at http://polymer.g
ithub.io/LICENSE.txt | |
4 The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | |
5 The complete set of contributors may be found at http://polymer.github.io/CONTRI
BUTORS.txt | |
6 Code distributed by Google as part of the polymer project is also | |
7 subject to an additional IP rights grant found at http://polymer.github.io/PATEN
TS.txt | |
8 --> | |
9 | |
10 <link rel="import" href="../polymer/polymer.html"> | |
11 <link rel="import" href="../promise-polyfill/promise-polyfill-lite.html"> | |
12 | |
13 <!-- | |
14 iron-request can be used to perform XMLHttpRequests. | |
15 | |
16 <iron-request id="xhr"></iron-request> | |
17 ... | |
18 this.$.xhr.send({url: url, params: params}); | |
19 --> | |
20 <script> | |
21 Polymer({ | |
22 is: 'iron-request', | |
23 | |
24 properties: { | |
25 | |
26 /** | |
27 * A reference to the XMLHttpRequest instance used to generate the | |
28 * network request. | |
29 * | |
30 * @attribute xhr | |
31 * @type XMLHttpRequest | |
32 * @default `new XMLHttpRequest` | |
33 */ | |
34 xhr: { | |
35 type: Object, | |
36 notify: true, | |
37 readOnly: true, | |
38 value: function() { | |
39 return new XMLHttpRequest(); | |
40 } | |
41 }, | |
42 | |
43 /** | |
44 * A reference to the parsed response body, if the `xhr` has completely | |
45 * resolved. | |
46 * | |
47 * @attribute response | |
48 * @type {*} | |
49 * @default null | |
50 */ | |
51 response: { | |
52 type: Object, | |
53 notify: true, | |
54 readOnly: true, | |
55 value: function() { | |
56 return null; | |
57 } | |
58 }, | |
59 | |
60 /** | |
61 * A promise that resolves when the `xhr` response comes back, or rejects | |
62 * if there is an error before the `xhr` completes. | |
63 * | |
64 * @attribute completes | |
65 * @type Promise | |
66 * @default `new Promise` | |
67 */ | |
68 completes: { | |
69 type: Object, | |
70 readOnly: true, | |
71 notify: true, | |
72 value: function() { | |
73 return new Promise(function (resolve, reject) { | |
74 this.resolveCompletes = resolve; | |
75 this.rejectCompletes = reject; | |
76 }.bind(this)); | |
77 } | |
78 }, | |
79 | |
80 /** | |
81 * An object that contains progress information emitted by the XHR if | |
82 * available. | |
83 * | |
84 * @attribute progress | |
85 * @type Object | |
86 * @default {} | |
87 */ | |
88 progress: { | |
89 type: Object, | |
90 notify: true, | |
91 readOnly: true, | |
92 value: function() { | |
93 return {}; | |
94 } | |
95 }, | |
96 | |
97 /** | |
98 * Aborted will be true if an abort of the request is attempted. | |
99 * | |
100 * @attribute aborted | |
101 * @type boolean | |
102 * @default false | |
103 */ | |
104 aborted: { | |
105 type: Boolean, | |
106 notify: true, | |
107 readOnly: true, | |
108 value: false, | |
109 } | |
110 }, | |
111 | |
112 /** | |
113 * Succeeded is true if the request succeeded. The request succeeded if the | |
114 * status code is greater-than-or-equal-to 200, and less-than 300. Also, | |
115 * the status code 0 is accepted as a success even though the outcome may | |
116 * be ambiguous. | |
117 * | |
118 * @return {boolean} | |
119 */ | |
120 get succeeded() { | |
121 var status = this.xhr.status || 0; | |
122 | |
123 // Note: if we are using the file:// protocol, the status code will be 0 | |
124 // for all outcomes (successful or otherwise). | |
125 return status === 0 || | |
126 (status >= 200 && status < 300); | |
127 }, | |
128 | |
129 /** | |
130 * Sends an HTTP request to the server and returns the XHR object. | |
131 * | |
132 * @param {{ | |
133 * url: string, | |
134 * method: (string|undefined), | |
135 * async: (boolean|undefined), | |
136 * body: (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|u
ndefined), | |
137 * headers: (Object|undefined), | |
138 * handleAs: (string|undefined), | |
139 * withCredentials: (boolean|undefined)}} options - | |
140 * url The url to which the request is sent. | |
141 * method The HTTP method to use, default is GET. | |
142 * async By default, all requests are sent asynchronously. To send synch
ronous requests, | |
143 * set to true. | |
144 * body The content for the request body for POST method. | |
145 * headers HTTP request headers. | |
146 * handleAs The response type. Default is 'text'. | |
147 * withCredentials Whether or not to send credentials on the request. De
fault is false. | |
148 * @return {Promise} | |
149 */ | |
150 send: function (options) { | |
151 var xhr = this.xhr; | |
152 | |
153 if (xhr.readyState > 0) { | |
154 return null; | |
155 } | |
156 | |
157 xhr.addEventListener('readystatechange', function () { | |
158 if (xhr.readyState === 4 && !this.aborted) { | |
159 | |
160 if (!this.succeeded) { | |
161 this.rejectCompletes(new Error('The request failed with status code:
' + this.xhr.status)); | |
162 return; | |
163 } | |
164 | |
165 this._setResponse(this.parseResponse()); | |
166 this.resolveCompletes(this); | |
167 } | |
168 }.bind(this)); | |
169 | |
170 xhr.addEventListener('progress', function (progress) { | |
171 this._setProgress({ | |
172 lengthComputable: progress.lengthComputable, | |
173 loaded: progress.loaded, | |
174 total: progress.total | |
175 }); | |
176 }.bind(this)) | |
177 | |
178 xhr.addEventListener('error', function (error) { | |
179 this.rejectCompletes(error); | |
180 }.bind(this)); | |
181 | |
182 xhr.addEventListener('abort', function () { | |
183 this.rejectCompletes(new Error('Request aborted.')); | |
184 }.bind(this)); | |
185 | |
186 xhr.open( | |
187 options.method || 'GET', | |
188 options.url, | |
189 options.async !== false | |
190 ); | |
191 | |
192 if (options.headers) { | |
193 Object.keys(options.headers).forEach(function (requestHeader) { | |
194 xhr.setRequestHeader( | |
195 requestHeader, | |
196 options.headers[requestHeader] | |
197 ); | |
198 }, this); | |
199 } | |
200 | |
201 // In IE, `xhr.responseType` is an empty string when the response | |
202 // returns. Hence, caching it as `xhr._responseType`. | |
203 xhr.responseType = xhr._responseType = (options.handleAs || 'text'); | |
204 xhr.withCredentials = !!options.withCredentials; | |
205 | |
206 xhr.send(options.body); | |
207 | |
208 return this.completes; | |
209 }, | |
210 | |
211 /** | |
212 * Attempts to parse the response body of the XHR. If parsing succeeds, | |
213 * the value returned will be deserialized based on the `responseType` | |
214 * set on the XHR. | |
215 * | |
216 * @return {*} The parsed response, | |
217 * or undefined if there was an empty response or parsing failed. | |
218 */ | |
219 parseResponse: function () { | |
220 var xhr = this.xhr; | |
221 var responseType = this.xhr.responseType || | |
222 this.xhr._responseType; | |
223 // If we don't have a natural `xhr.responseType`, we prefer parsing | |
224 // `xhr.responseText` over returning `xhr.response`.. | |
225 var preferResponseText = !this.xhr.responseType; | |
226 | |
227 try { | |
228 switch (responseType) { | |
229 case 'json': | |
230 // If xhr.response is undefined, responseType `json` may | |
231 // not be supported. | |
232 if (preferResponseText || xhr.response === undefined) { | |
233 // If accessing `xhr.responseText` throws, responseType `json` | |
234 // is supported and the result is rightly `undefined`. | |
235 try { | |
236 xhr.responseText; | |
237 } catch (e) { | |
238 return xhr.response; | |
239 } | |
240 | |
241 // Otherwise, attempt to parse `xhr.responseText` as JSON. | |
242 if (xhr.responseText) { | |
243 return JSON.parse(xhr.responseText); | |
244 } | |
245 } | |
246 | |
247 return xhr.response; | |
248 case 'xml': | |
249 return xhr.responseXML; | |
250 case 'blob': | |
251 case 'document': | |
252 case 'arraybuffer': | |
253 return xhr.response; | |
254 case 'text': | |
255 default: | |
256 return xhr.responseText; | |
257 } | |
258 } catch (e) { | |
259 this.rejectCompletes(new Error('Could not parse response. ' + e.message)
); | |
260 } | |
261 }, | |
262 | |
263 /** | |
264 * Aborts the request. | |
265 */ | |
266 abort: function () { | |
267 this._setAborted(true); | |
268 this.xhr.abort(); | |
269 } | |
270 }); | |
271 </script> | |
272 | |
OLD | NEW |