iron-request doesn't make more than one request - javascript

I am working with the Polymer 2 library. Whenever I try to make multiple requests using iron-request, the code only ever seems to make a POST request on the first initiation. Any subsequent requests seem to be ignored, even when data that is set to be sent to the server is different from the initial request.
I've written a small example in this Plunker: https://plnkr.co/edit/cozVKUdQ2q2SV46rcCTL?p=preview
I created a iron-request and a button element to initiate the request like so:
<paper-button on-click="save" class="green">Send</paper-button>
...
<iron-request id="xhr"></iron-request>
The save function is setup to take text from a textarea and send that off to a server.
save() {
var response = this.$.xhr.send({
url: "https://httpbin.org/post",
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
body: {
content: this.inputdata
},
method: "POST"
});
var poly = this;
this.$.xhr.completes.then(function(data) {
console.log("finished");
poly.$.responsetext.innerHTML = data.response;
})
The code in question is in the "element1.html" file. If you try sending different text payloads, only the first request will be send. (You can see in the response box that the form "content" field stays the same.)
Any idea what is going on? I'm thinking that I would have to create new iron-request elements everytime I need to make a new request... but that doesn't sound like a very elegant solution.

As you suspected, iron-request has been built to send a single HTTP request. I had a quick look at the its implementation. The send method will actually just return null and not do anything, if the request has a status that is larger 0 than, which will be the case if you have used it before.
While you could create a new iron-request element for each request, it is not elegant (as you said yourself). Instead, you could work with iron-ajax. You can find some instructions on its documentation page.
Your <iron-request> can be rewritten as this.
<iron-ajax id="xhr" url="https://httpbin.org/post" content-type="application/x-www-form-urlencoded" method="POST" body="[[inputdata]]" on-response="onXhrSuccess"></iron-ajax>
Your save function,
save() {
this.$.xhr.generateRequest();
}
onXhrSuccess(event, request) {
console.log("finished");
poly.$.responsetext.innerHTML = event.detail.response;
}

Related

Javascript: How did I get here? (Viewing data sent by server, non-AJAX.)

I've got a React-based app that works like this: The user makes a request for "foo", the server returns basic page info (applicable to all pages on the site), and when the client receives this (DOMContentLoaded), it does an AJAX call for the internal details "foo" and renders that.
But is it possible, if I send the data on the first request, to skip the AJAX call? (I tried this previously but was very new to React, which is how I came up with the current scheme. It's come up again because now I'm handling previously saved items.) So, I'm in my DOMContentLoaded listener, and I can see (in the Browser|Network|Response area of Chrome) all the data that has been sent by the server. It's everything I need, and it's right there, but I can't find a way to access it in Javascript.
The searches I've done have almost all turned up AJAX requests. (I am using JQuery, if that helps.) Obviously I can handle loading saved data using the same gag I'm currently using, and maybe that's a an all-around better approach.
So, once again, the question is: Is it possible to look at the response from a non-AJAX place? If it is possible, is it advisable?
Update: Let me walk through an example scenario.
The user goes to "/foo".
The server response is {:some "json"}.
In the Javascript onReady, I can do this:
console.log(window.location);
and I'll see "/foo". But can I see {:some "json"}? And how? Contrast with the AJAX call version:
The user goes to "/foo".
The server response is nothing (i.e., a 200 but no body).
The Javascript onReady has:
$.ajax({
url: "/foo/data"
type: "GET",
success: function (req) {...} //req has {:some data} in it!
So, when I make an AJAX call, I get the request. Is there any way to get that {:some data} on a non-AJAX call? This doesn't work, but I could see something like:
x = window.response();
or
x = Response.last();
Neither of those things exist, of course. I hope that clarifies what I'm looking for.
You could drop a script tag on your server-rendered page that includes a global var accessible by your script bundle. e.g.,
<script>
var myGlobalVar = { ... server data ... } <!-- // note: this is rendered raw by your server
</script>
<script src="myScriptBundle.min.js"></script>
Or, alternatively you could look into server-side rendering, which is possible with React. Check out the implementation in Redux: http://redux.js.org/docs/recipes/ServerRendering.html

Upload image by Froala to server with custom response format

I am using Froala editor.
I would like to upload images to own server, as described in documentation response format should be { link: 'path/to/image.jpg' }, but my server returns response with another format.
Is it possible to use custom response format with Froala, probably by handle some event?
there is nothing to do with the server response model via the front. its model is designed at backend and if you need to change it you maye parse the Json you get and change the model as you wish. to get the model exactly as you mentioned above you should talk to your backend team.
I'm using cloudinary.com for uploading and serving images and I also have no control on the response. My temporary solution was to monkey patch the JSON.parse method like this (coffeescript) :
var _parseJSON = JSON.parse;
JSON.parse = function(j) {
var response = _parseJSON(j);
response.link = response.secure_url;
return response;
};
I really hope to find a more elegant solution!
Froala seems to not have a mechanism to modify the response from the server when it manages uploads. There is a suitable froala event for this froalaEditor.file.uploaded, but it only can abort the upload process. May be in the future it will be updated to suit such cases
However what you want is absolutely doable. First you'll need to add a query param to imageUploadURL prop in your froala config, e.g. const froalaConfig = {imageUploadURL: '/yourUploadsEndpoint?fromFroala'}. This param is needed to distinguish requests that were actually made by froala from others.
Then we will do a little monkey patch to XMLHttpRequestObject, which is internally used by froala to make http requests:
const accessor = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'responseText')
Object.defineProperty(XMLHttpRequest.prototype, 'responseText', {
get() {
const responseText = accessor.get.call(this)
// here we can check if response url includes our previously set query param
if (this.responseURL.includes('?fromFroala')) {
// r is our response object
const r = JSON.parse(responseText)
return JSON.stringify({ link: <path to your uploaded image url here> })
}
return responseText
},
configurable: true,
})
This should do the trick until froala switches to another data fetching API.
The image.uploaded event is being triggered as soon as there is a response from the server. You could use the response parameter of this event together with the image.insert method to add the image in the editor.
Also, it is important to return false at the end of the callback to prevent the default editor upload chain.
Below is a code snippet for that:
$('.selector')
.froalaEditor()
.on('froalaEditor.image.uploaded', function (e, editor, response) {
// Parse response to get image url.
var img_url = ... ;
// Insert image.
editor.image.insert(img_url, false, null, editor.image.get(), response);
return false;
});

Meteor.call() - can it be aborted (stopped before it finishes)?

Let's say we have a grid, and the data comes from the server Meteor.call(). When user clicks on the pagination, or changes sorting or filtering options, some animation is shown, and the method is called. Once data comes back, we hide the animation and render the list. This works great, but we would also like to abort current call if the user changes their mind before data comes back and goes to another page, or changes another filter. Is there a way to do that? In AngularJS I used .abort() on ajax http requests, and that worked perfectly... is Meteor lacking a similar function?
You can use beforeSend option for that:
var requestObject;
HTTP.call("GET", url, {
beforeSend: req => requestObject = req
}, (error, result) => {
// do your stuff ...
});
requestObject.abort();
Note: at the time of writing this is only supported on client.

Run (JS) function if server responded something specific

On one of my pages I have "tracking.php" that makes a request to another server, and if tracking is sucessful in Firebug Net panel I see the response trackingFinished();
Is there an easy way (built-in function) to accomplish something like this:
If ("tracking.php" responded "trackingFinished();") { *redirect*... }
Javascript? PHP? Anything?
The thing is, this "tracking.php" also creates browser and flash cookies (and then responds with trackingfinished(); when they're created). I had a JS that did something like this:
If ("MyCookie" is created) { *redirect*... }
It worked, but if you had MyCookie in your browser from before, it just redirected before "track.php" had the time to create new cookies, so old cookies didn't get overwritten (which I'm trying to accomplish) before the redirection...
The solution I have in mind is to redirect after trackingFinished(); was responded...
I think the better form in javascript to make request from one page to another, without leaving the first is with the ajax method, and this one jQuery make it so easy, you only have to use the ajax function, and pass a little parameters:
$.post(url, {parameter1: parameter1value, param2: param2value})
And you can concatenate some actions:
$.post().done(function(){}).fail(function(){})
And isntead of the ajax, you can use the $.post that is more easy, and use the done and fail method to evaluate the succes of the information recived
As mentioned above, AJAX is the best way to communicate between pages like this. Here's an example of an AJAX request to your track.php page. It uses the success function to see if track.php returned 'trackingFinished();'. If it did then it redirects the page 'redirect.php':
$.ajax({
url: "track.php",
dataType: "text",
success: function(data){
if(data === 'trackingFinished();'){
document.location = 'redirect.php';
}
}
});
The example uses JQuery.

Any function with mixed functionality of .ajax() and .load()?

.ajax() can send a post request and get data in return where as .load() can get any element in the rendered page. How to create a form when submitted(asynchromously) instead of getting back some data should get the page element of the rendered page that would be generated had there been normal submission instead of ajax submission?
I dont want to write views(Django) for xhr, normal requests separately. So, When I submit a form by ajax I dont want to hijack default action but only want to get some element of the rendered post submission page instead of actually being redirected to that post submission page which would have happened hadn't it been an xhr request.
Update:
load will do a POST rather than a GET if you supply the data to send as an object rather than a string. From the docs:
Request Method
The POST method is used if data is provided as an object; otherwise, GET is assumed.
So:
$("#target").load("/path/to/resource selector_for_relevant_elements", {});
..should convert the load from GET to POST. Of course, you'd replace {} with the arguments you want to send.
Original answer:
You can do the POST directly with ajax and then process the returned HTML yourself. For instance, to turn this load:
$("#target").load("/path/to/resource selector_for_relevant_elements");
..into a POST:
$.ajax({
url: "/path/to/resource",
method: "POST",
dataType: "html",
success: function(html) {
// Build the elemnts of the result in a disconnected document
var page = $("<div>").append(html); // See note below
// Find the relevant elements and put them in target
$("#target").html(page.find("selector_for_relevant_elements"));
}
});
I've done the wrapper div because that's what jQuery's load function does. You may want to look at the source for load (that line number will rot, of course, but the filename is unlikely to change) to see if there are other tricks you need to replicate.

Categories

Resources