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="iron-request.html"> | |
12 | |
13 <!-- | |
14 The `iron-ajax` element exposes network request functionality. | |
15 | |
16 <iron-ajax | |
17 auto | |
18 url="http://gdata.youtube.com/feeds/api/videos/" | |
19 params='{"alt":"json", "q":"chrome"}' | |
20 handle-as="json" | |
21 on-response="handleResponse" | |
22 debounce-duration="300"></iron-ajax> | |
23 | |
24 With `auto` set to `true`, the element performs a request whenever | |
25 its `url`, `params` or `body` properties are changed. Automatically generated | |
26 requests will be debounced in the case that multiple attributes are changed | |
27 sequentially. | |
28 | |
29 Note: The `params` attribute must be double quoted JSON. | |
30 | |
31 You can trigger a request explicitly by calling `generateRequest` on the | |
32 element. | |
33 | |
34 @demo demo/index.html | |
35 --> | |
36 | |
37 <script> | |
38 | |
39 Polymer({ | |
40 | |
41 is: 'iron-ajax', | |
42 | |
43 /** | |
44 * Fired when a request is sent. | |
45 * | |
46 * @event request | |
47 */ | |
48 | |
49 /** | |
50 * Fired when a response is received. | |
51 * | |
52 * @event response | |
53 */ | |
54 | |
55 /** | |
56 * Fired when an error is received. | |
57 * | |
58 * @event error | |
59 */ | |
60 | |
61 properties: { | |
62 /** | |
63 * The URL target of the request. | |
64 */ | |
65 url: { | |
66 type: String, | |
67 value: '' | |
68 }, | |
69 | |
70 /** | |
71 * An object that contains query parameters to be appended to the | |
72 * specified `url` when generating a request. If you wish to set the body | |
73 * content when making a POST request, you should use the `body` property | |
74 * instead. | |
75 */ | |
76 params: { | |
77 type: Object, | |
78 value: function() { | |
79 return {}; | |
80 } | |
81 }, | |
82 | |
83 /** | |
84 * The HTTP method to use such as 'GET', 'POST', 'PUT', or 'DELETE'. | |
85 * Default is 'GET'. | |
86 */ | |
87 method: { | |
88 type: String, | |
89 value: 'GET' | |
90 }, | |
91 | |
92 /** | |
93 * HTTP request headers to send. | |
94 * | |
95 * Example: | |
96 * | |
97 * <iron-ajax | |
98 * auto | |
99 * url="http://somesite.com" | |
100 * headers='{"X-Requested-With": "XMLHttpRequest"}' | |
101 * handle-as="json" | |
102 * last-response-changed="{{handleResponse}}"></iron-ajax> | |
103 * | |
104 * Note: setting a `Content-Type` header here will override the value | |
105 * specified by the `contentType` property of this element. | |
106 */ | |
107 headers: { | |
108 type: Object, | |
109 value: function() { | |
110 return {}; | |
111 } | |
112 }, | |
113 | |
114 /** | |
115 * Content type to use when sending data. If the `contentType` property | |
116 * is set and a `Content-Type` header is specified in the `headers` | |
117 * property, the `headers` property value will take precedence. | |
118 */ | |
119 contentType: { | |
120 type: String, | |
121 value: 'application/x-www-form-urlencoded' | |
122 }, | |
123 | |
124 /** | |
125 * Optional raw body content to send when method === "POST". | |
126 * | |
127 * Example: | |
128 * | |
129 * <iron-ajax method="POST" auto url="http://somesite.com" | |
130 * body='{"foo":1, "bar":2}'> | |
131 * </iron-ajax> | |
132 */ | |
133 body: { | |
134 type: String, | |
135 value: '' | |
136 }, | |
137 | |
138 /** | |
139 * Toggle whether XHR is synchronous or asynchronous. Don't change this | |
140 * to true unless You Know What You Are Doing™. | |
141 */ | |
142 sync: { | |
143 type: Boolean, | |
144 value: false | |
145 }, | |
146 | |
147 /** | |
148 * Specifies what data to store in the `response` property, and | |
149 * to deliver as `event.response` in `response` events. | |
150 * | |
151 * One of: | |
152 * | |
153 * `text`: uses `XHR.responseText`. | |
154 * | |
155 * `xml`: uses `XHR.responseXML`. | |
156 * | |
157 * `json`: uses `XHR.responseText` parsed as JSON. | |
158 * | |
159 * `arraybuffer`: uses `XHR.response`. | |
160 * | |
161 * `blob`: uses `XHR.response`. | |
162 * | |
163 * `document`: uses `XHR.response`. | |
164 */ | |
165 handleAs: { | |
166 type: String, | |
167 value: 'json' | |
168 }, | |
169 | |
170 /** | |
171 * Set the withCredentials flag on the request. | |
172 */ | |
173 withCredentials: { | |
174 type: Boolean, | |
175 value: false | |
176 }, | |
177 | |
178 /** | |
179 * If true, automatically performs an Ajax request when either `url` or | |
180 * `params` changes. | |
181 */ | |
182 auto: { | |
183 type: Boolean, | |
184 value: false | |
185 }, | |
186 | |
187 /** | |
188 * If true, error messages will automatically be logged to the console. | |
189 */ | |
190 verbose: { | |
191 type: Boolean, | |
192 value: false | |
193 }, | |
194 | |
195 /** | |
196 * Will be set to true if there is at least one in-flight request | |
197 * associated with this iron-ajax element. | |
198 */ | |
199 loading: { | |
200 type: Boolean, | |
201 notify: true, | |
202 readOnly: true | |
203 }, | |
204 | |
205 /** | |
206 * Will be set to the most recent request made by this iron-ajax element. | |
207 */ | |
208 lastRequest: { | |
209 type: Object, | |
210 notify: true, | |
211 readOnly: true | |
212 }, | |
213 | |
214 /** | |
215 * Will be set to the most recent response received by a request | |
216 * that originated from this iron-ajax element. The type of the response | |
217 * is determined by the value of `handleAs` at the time that the request | |
218 * was generated. | |
219 */ | |
220 lastResponse: { | |
221 type: Object, | |
222 notify: true, | |
223 readOnly: true | |
224 }, | |
225 | |
226 /** | |
227 * Will be set to the most recent error that resulted from a request | |
228 * that originated from this iron-ajax element. | |
229 */ | |
230 lastError: { | |
231 type: Object, | |
232 notify: true, | |
233 readOnly: true | |
234 }, | |
235 | |
236 /** | |
237 * An Array of all in-flight requests originating from this iron-ajax | |
238 * element. | |
239 */ | |
240 activeRequests: { | |
241 type: Array, | |
242 notify: true, | |
243 readOnly: true, | |
244 value: function() { | |
245 return []; | |
246 } | |
247 }, | |
248 | |
249 /** | |
250 * Length of time in milliseconds to debounce multiple requests. | |
251 */ | |
252 debounceDuration: { | |
253 type: Number, | |
254 value: 0, | |
255 notify: true | |
256 }, | |
257 | |
258 _boundHandleResponse: { | |
259 type: Function, | |
260 value: function() { | |
261 return this._handleResponse.bind(this); | |
262 } | |
263 } | |
264 }, | |
265 | |
266 observers: [ | |
267 '_requestOptionsChanged(url, method, params, headers,' + | |
268 'contentType, body, sync, handleAs, withCredentials, auto)' | |
269 ], | |
270 | |
271 /** | |
272 * The query string that should be appended to the `url`, serialized from | |
273 * the current value of `params`. | |
274 * | |
275 * @return {string} | |
276 */ | |
277 get queryString () { | |
278 var queryParts = []; | |
279 var param; | |
280 var value; | |
281 | |
282 for (param in this.params) { | |
283 value = this.params[param]; | |
284 param = window.encodeURIComponent(param); | |
285 | |
286 if (value !== null) { | |
287 param += '=' + window.encodeURIComponent(value); | |
288 } | |
289 | |
290 queryParts.push(param); | |
291 } | |
292 | |
293 return queryParts.join('&'); | |
294 }, | |
295 | |
296 /** | |
297 * The `url` with query string (if `params` are specified), suitable for | |
298 * providing to an `iron-request` instance. | |
299 * | |
300 * @return {string} | |
301 */ | |
302 get requestUrl() { | |
303 var queryString = this.queryString; | |
304 | |
305 if (queryString) { | |
306 return this.url + '?' + queryString; | |
307 } | |
308 | |
309 return this.url; | |
310 }, | |
311 | |
312 /** | |
313 * An object that maps header names to header values, first applying the | |
314 * the value of `Content-Type` and then overlaying the headers specified | |
315 * in the `headers` property. | |
316 * | |
317 * @return {Object} | |
318 */ | |
319 get requestHeaders() { | |
320 var headers = { | |
321 'Content-Type': this.contentType | |
322 }; | |
323 var header; | |
324 | |
325 if (this.headers instanceof Object) { | |
326 for (header in this.headers) { | |
327 headers[header] = this.headers[header].toString(); | |
328 } | |
329 } | |
330 | |
331 return headers; | |
332 }, | |
333 | |
334 /** | |
335 * Request options suitable for generating an `iron-request` instance based | |
336 * on the current state of the `iron-ajax` instance's properties. | |
337 * | |
338 * @return {{ | |
339 * url: string, | |
340 * method: (string|undefined), | |
341 * async: (boolean|undefined), | |
342 * body: (ArrayBuffer|ArrayBufferView|Blob|Document|FormData|null|string|u
ndefined), | |
343 * headers: (Object|undefined), | |
344 * handleAs: (string|undefined), | |
345 * withCredentials: (boolean|undefined)}} | |
346 */ | |
347 toRequestOptions: function() { | |
348 return { | |
349 url: this.requestUrl, | |
350 method: this.method, | |
351 headers: this.requestHeaders, | |
352 body: this.body, | |
353 async: !this.sync, | |
354 handleAs: this.handleAs, | |
355 withCredentials: this.withCredentials | |
356 }; | |
357 }, | |
358 | |
359 /** | |
360 * Performs an AJAX request to the specified URL. | |
361 * | |
362 * @return {!IronRequestElement} | |
363 */ | |
364 generateRequest: function() { | |
365 var request = /** @type {!IronRequestElement} */ (document.createElement('
iron-request')); | |
366 var requestOptions = this.toRequestOptions(); | |
367 | |
368 this.activeRequests.push(request); | |
369 | |
370 request.completes.then( | |
371 this._boundHandleResponse | |
372 ).catch( | |
373 this._handleError.bind(this, request) | |
374 ).then( | |
375 this._discardRequest.bind(this, request) | |
376 ); | |
377 | |
378 request.send(requestOptions); | |
379 | |
380 this._setLastRequest(request); | |
381 this._setLoading(true); | |
382 | |
383 this.fire('request', { | |
384 request: request, | |
385 options: requestOptions | |
386 }); | |
387 | |
388 return request; | |
389 }, | |
390 | |
391 _handleResponse: function(request) { | |
392 this._setLastResponse(request.response); | |
393 this.fire('response', request); | |
394 }, | |
395 | |
396 _handleError: function(request, error) { | |
397 if (this.verbose) { | |
398 console.error(error); | |
399 } | |
400 | |
401 this._setLastError({ | |
402 request: request, | |
403 error: error | |
404 }); | |
405 this.fire('error', { | |
406 request: request, | |
407 error: error | |
408 }); | |
409 }, | |
410 | |
411 _discardRequest: function(request) { | |
412 var requestIndex = this.activeRequests.indexOf(request); | |
413 | |
414 if (requestIndex > -1) { | |
415 this.activeRequests.splice(requestIndex, 1); | |
416 } | |
417 | |
418 if (this.activeRequests.length === 0) { | |
419 this._setLoading(false); | |
420 } | |
421 }, | |
422 | |
423 _requestOptionsChanged: function() { | |
424 this.debounce('generate-request', function() { | |
425 if (!this.url && this.url !== '') { | |
426 return; | |
427 } | |
428 | |
429 if (this.auto) { | |
430 this.generateRequest(); | |
431 } | |
432 }, this.debounceDuration); | |
433 }, | |
434 | |
435 }); | |
436 </script> | |
OLD | NEW |