I am having an issue trying to improve the functionality of my ajax functions by adding arguments to define what to do with the returned result.
So what i am trying to implement is a way to tell the function to append the result to a given element by its id. But i am having difficulty understanding how to add this functionality.
This is my current code:
var ajax = new function(){
var self = this;
self.x = function() {
if (typeof XMLHttpRequest !== 'undefined') {
return new XMLHttpRequest();
}
};
self.send = function(url, callback, method, data, sync) {
var x = self.x();
x.open(method, url, sync);
x.onreadystatechange = function() {
if (x.readyState == 4) {
callback(x.responseText)
}
};
if (method == 'POST') {
x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
}
x.send(data)
};
self.get = function(url, data, callback, sync) {
var query = [];
for (var key in data) {
query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
}
self.send(url + (query.length ? '?' + query.join('&') : ''), callback, 'GET', null, sync)
};
};
I then make an ajax request like so:
//get the html file, and then call a function
ajax.get(dir.layout+'login.html',false,
function(){
elements.addTemplate(data,'parent',true);
});
In Chrome the xhr shows the correct data and contents, so i know that part works. In my elements.loadTemplate function i have these three lines with their actual values:
elements.addtemplate(data,div_id,append){
console.log(data); //shows:
console.log(div_id); //shows string: parent
console.log(append); //shows: true
}
Now the issue is data is blank, when i want it to contain the contents of the HTML file that I just requested (in this case login.html). I am wondering why it would show up as blank and how i can fix it?
your data is undefined because your callback doesn't accept a parameter
try this:
ajax.get(dir.layout+'login.html',false,
function(data){ // <=== data
elements.addTemplate(data,'parent',true);
});
Related
So, I have a list of data that I am out putting onto my view, and each list item has an id.
Each of these list items is a bar and I have a document created for each bar that at least one user is going to. For those bars where no users are going, there is no document created.
I need to make an AJAX call for each list item to the database to check
i) If a document exists for that list item
ii) If a document exists, how many users are going according to the document.
I attempted a solution using a while loop, where the update for the while loop was contained in the callback for the AJAX call. Here is the code
function updateAllGoingButtons(){
var i = 0;
var dataToPass = {};
var numButtons = global_data_object.listData.businesses.length;
while(i < numButtons){
dataToPass.button = global_data_object.listData.businesses[i].id;
dataToPass = JSON.stringify(dataToPass);
ajaxFunctions.ready(ajaxFunctions.ajaxRequest('POST', '/update-buttons', dataToPass, function(data){
console.log(i);
i++;
}));
}
}
When I attempted to run the function, I got the error,
Request entity too large
So, is there a better way to go about doing what I am trying to do? Should I use promises? Or is there simply an error in the way I am trying to make the AJAX call from within a while loop?
For reference, here is the ajaxRequest function
'use strict';
var appUrl = window.location.origin;
var ajaxFunctions = {
ready: function ready (fn) {
if (typeof fn !== 'function') {
return;
}
if (document.readyState === 'complete') {
return fn();
}
document.addEventListener('DOMContentLoaded', fn, false);
},
ajaxRequest: function ajaxRequest (method, url, data, callback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
callback(xmlhttp.response);
}
};
xmlhttp.open(method, url, true);
xmlhttp.setRequestHeader('Content-type', 'application/json');
xmlhttp.send(data);
}
};
You should check out the npm library called async, it has an each method that you can do asynchronous calls within. If you use promises, the Promise.all method in Bluebird could be very useful for you.
So, here's how I did the multiple AJAX calls from within a loop. I used this resource https://medium.com/coding-design/writing-better-ajax-8ee4a7fb95f#.d7ymg99mp (Great resource!)
Here's the code
$('.btn-group').find('button').each(function() {
console.log($(this).attr('id'));
dataToPass.button = $(this).attr('id');
var ajax = $.ajax({
url: '/update-buttons',
method: 'post',
data: dataToPass,
dataType: 'json',
}).success(function(data){
console.log(data);
});
});
Essentially, what this does is selects a div with the class 'btn-group' and then iterates over each button within that div using the jQuery each operator. Then simply make an AJAX request and use the success chain callback to access the returned data.
I have the following http variable which returns an object:
var http = (function(){
var success = null;
var error = null;
var requestInfo = {content: '', status: 0};
var core = {
request: function(options){
var $http = Object.create(http);
sendRequest(options).then(function(){
if(typeof(success) == 'function'){
success(requestInfo.content);
}
}, function(){
if(typeof(error) == 'function'){
error(requestInfo.content);
}
});
return $http;
},
success: function(callback){
success = callback;
return this;
},
error: function(callback){
error = callback;
return this;
}
};
function sendRequest(options){
return new Promise(function(resolve, reject){
var xhttp = new XMLHttpRequest();
var method = options.method.toUpperCase();
xhttp.onreadystatechange = function() {
if(xhttp.readyState == 4){
requestInfo.content = JSON.parse(xhttp.responseText) || xhttp.responseText;
requestInfo.status = xhttp.status;
}
if (xhttp.readyState == 4 && xhttp.status == 200) {
resolve(requestInfo);
}else if(xhttp.readyState == 4 && xhttp.status != 200){
reject(requestInfo);
}else if(xhttp.status >= 400){
reject(requestInfo);
}
};
xhttp.open((method || 'GET'), options.url, true);
var data = options.data || '';
xhttp.setRequestHeader('X-CSRF-TOKEN', document.querySelector('meta[name="csrf-token"]').getAttribute('content'));
if((typeof(data) == 'object' && (Object.keys(data).length > 0) || data.length > 0)){
xhttp.send(JSON.stringify(data));
}else{
xhttp.send();
}
});
}
return core;
})();
If I call it more than once simultaneously, like so:
http.request({url: '/path1'}).success(function(){
alert('success');
});
http.request({url: '/path2'}).success(function(){
alert('success');
});
only one of the items gets passed via ajax the other one does not. What is causing this? I thought that doing Object.create(this) would make each one unique from each other but it doesn't seem to be doing that...
The Object.create() method creates a new object with the specified prototype object and properties.
So you're creating 2 objects with the same prototype, and the data is in the prototype itself. Since the prototype is an object, and it is the same, both resulting objects have the same references for their data objects and functions.
You need to specify the data not in the prototype object, but for each instance instead.
So after you create var $this = Object.create(this);, you must add the data to $this, such as successFunc, otherwise the next call will override this data.
The sucessand error variable used to store your callback functions must be created within your request function to be truly unique per request. However, if you're going to use Promises, I'd suggest simplifying the whole deal using load and error event listeners available to the XMLHttpRequest object (a nice example can be found on MDN's XMLHttpRequest article) and simply passing in your success and failure functions the then method of your Promise instance.
Here's a simplified JSFiddle example using a timeout to simulate a 500 millisecond HTTP request.
The issue was with this line:
var method = options.method.toUpperCase();
I was not setting the method property in the options and it wasn't erroring saying that it couldn't send, it basically just exited the method without warning...
I changed it to this:
var method = (options.method || 'GET').toUpperCase();
and it started to work.
I have a CSV which has placement links and target links in the format
e.g
CSV Sample
[placement url],[target url]
[placement url],[target url]
[placement url],[target url]
and i need to read the CSV, line by line using javascript and fetch the placement urls's [Page Title] and then post to a PHP script that i already have, each
[Page Title] and its respect [target URL].
So this is what i have for the javascript
for (i = 1; i < csvLines.length; i++) {
csvValues = csvLines[i].split(";");
pagetitle = csvValues[0];
target = csvValues[1];
/*start ajax*/
$.ajax({
url: pagetitle,
dataType: 'html',
statusCode: {
200: function(response) {
var matches = response.match(/<title>(.*?)<\/title>/);
placementTitles.push($(matches[0]).text());
targetURLS.push(?);
},
404: function() {
/*404 here*/
}
},
error: function(error) {
}
});
/*end ajax*/
}
My Question
Which value should i push into targetURLS array on targetURLS.push(?);, such that placementTitles[x] will always have its respective target URL in targetURLS[x]...putting into consideration these operations are asynchronous but still need to maintain the integrity of the CSV by always relating the 2 columns by using the same array index.
Alright, I found a better solution..
First we store all correlating data in one array [{url, target, response}, {url, target, response}] so the array index is the same for all.
Second we write (or overwrite if you like) our own ajax.get function in which we can add an additional parameter to the callback function (the array index).
<html>
<head>
<script src = 'jquery-1.9.1.min.js'></script>
<script>
//We write our own $.get to pass a parameter to it
AJAX = {
getXmlDoc: function(){return ((window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP"))},
//u:= url, f:= callback, c:=caller (here array index)
Get: function(u, f, c){
var tDoc = this.getXmlDoc();
tDoc.open('GET', u, true);
tDoc.onreadystatechange = function(){
//If you want to check others, change accordingly.
if (tDoc.readyState === XMLHttpRequest.DONE && tDoc.status === 200) f(tDoc, c);
};
tDoc.send();
}
};
</script>
<script type = 'text/javascript'>
var mCSV = ['url;key', 'url;key'];
var mResults = []; //This will hold our results.
function test(){
var mResults = [];
for(var i=0, j=mCSV.length;i<j;i++){
var tS = mCSV[i].split(';');
mResults.push({url: tS[0], target: tS[1]});
AJAX.Get(tS[0], function(r, i){
mResults[i].handled = true;
if (r.status === 200){
mResults[i].response = $(r.responseText.match(/<title>(.*?)<\/title>/)[0]).text();
console.log(mResults[i]);
};
}, i);
};
}
</script>
</head>
<body onload = 'test()'>
</body>
</html>
After watching RailsCast #296 about Mercury Editor, I am trying to get the editor to redirect to a newly created resource.
I can already redirect on the client-side using JS and window.location.href=. But for a new resource, I cannot "guess" its URL on the client-side. I need it to be in the server response.
However, the problem is that I don't see the possibility of using the server response in the editor. No matter what the controller renders, the server response is discarded by Mercury instead of used as an argument to my function for mercury:saved.
Is there a way to get around this?
I was able to do this on update by sending a valid JSON string back. I would assume create works the same way. check firebug to make sure you're not getting an error in the jQuery.ajax call that Mercury uses.
posts_controller.rb
def mercury_update
post = Post.find(params[:id])
post.title = params[:content][:post_title][:value]
post.body = params[:content][:post_body][:value]
post.save!
render text: '{"url":"'+ post_path(post.slug) +'"}'
end
mercury.js:
jQuery(window).on('mercury:ready', function() {
Mercury.on('saved', function() {
window.location.href = arguments[1].url
});
});
note: I'm using friendly_id to slug my posts
Redirecting on the server side doesn't work because the save button is just an jQuery.ajax call:
// page_editor.js
PageEditor.prototype.save = function(callback) {
var data, method, options, url, _ref, _ref1,
_this = this;
url = (_ref = (_ref1 = this.saveUrl) != null ? _ref1 : Mercury.saveUrl) != null ? _ref : this.iframeSrc();
data = this.serialize();
data = {
content: data
};
if (this.options.saveMethod === 'POST') {
method = 'POST';
} else {
method = 'PUT';
data['_method'] = method;
}
Mercury.log('saving', data);
options = {
headers: Mercury.ajaxHeaders(),
type: method,
dataType: this.options.saveDataType,
data: data,
success: function(response) {
Mercury.changes = false;
Mercury.trigger('saved', response);
if (typeof callback === 'function') {
return callback();
}
},
error: function(response) {
Mercury.trigger('save_failed', response);
return Mercury.notify('Mercury was unable to save to the url: %s', url);
}
};
if (this.options.saveStyle !== 'form') {
options['data'] = jQuery.toJSON(data);
options['contentType'] = 'application/json';
}
return jQuery.ajax(url, options);
};
So your redirect is sent to the success callback, but the page doesn't actually re-render, as with any successful AJAX request. The author discusses overriding this very function here. It also looks like there might be some room to maneuver here by passing a callback function to save.
Btw, another way to do what #corneliusk suggests is:
render { json: {url: post_path(post.slug)} }
Either way, the response body is passed as an argument to the function in the mercury:saved callback.
I am quite new to JavaScript libraries. I wanted to replace my current code with jQuery. My current code looks like this:
var req;
function createRequest() {
var key = document.getElementById("key");
var keypressed = document.getElementById("keypressed");
keypressed.value = key.value;
var url = "/My_Servlet/response?key=" + escape(key.value);
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
req.open("Get", url, true);
req.onreadystatechange = callback;
req.send(null);
}
function callback() {
if (req.readyState == 4) {
if (req.status == 200) {
var decimal = document.getElementById('decimal');
decimal.value = req.responseText;
}
}
clear();
}
I wanted to replace my code with something a little friendlier like jQuery's
$.get(url, callback);
However it doesn't call my callback function.
Also I would like to call a function called createRequest continuously. Does jQuery have a nice way of doing that?
$.get(url, {}, callback);
should do the trick. Your callback could be simplified like this:
function callback(content){
$('#decimal').val(content);
}
Or even shorter:
$.get(url, {}, function(content){
$('#decimal').val(content);
});
And all in all I think this should work:
function createRequest() {
var keyValue = $('#key').val();
$('#keypressed').val(keyValue);
var url = "/My_Servlet/response";
$.get(url, {key: keyValue}, function(content){
$('#decimal').val(content);
});
}
Take out the readyState and status checks. jQuery only calls your callback upon success. Your callback is supplied the arguments (data, textStatus), so you should use data instead of req.responseText.
window.setTimeout() as suggested by another answer won't do what you want - that only waits and then calls your function once. You need to use window.setInterval() instead, which will call your function periodically until you cancel it.
So, in summary:
var interval = 500; /* Milliseconds between requests. */
window.setInterval(function() {
var val = $("#key").val();
$("#keypressed").val(val);
$.get("/My_Servlet/response", { "key": val }, function(data, textStatus) {
$("#decimal").val(data);
});
}), interval);
I don't think jQuery implements a timeout function, but plain old javascript does it rather nicely :)
According to the docs, jQuery.get's arguments are url, data, callback, not url, callback.
A call to JavaScript's setTimeout function at the end of your callback function should suffice to get this to continually execute.
There's no need to set the GET parameters on the URL, jQuery will set them automatically. Try this code:
var key = document.getElementById("key");
[...]
var url = "/My_Servlet/response";
$.get (url, {'key': key}, function (responseText)
{
var decimal = document.getElementById ('decimal');
decimal.value = responseText;
});
In the end I guess it was added the type. This seems to work for me.
function convertToDecimal(){
var key = document.getElementById("key");
var keypressed = document.getElementById("keypressed");
keypressed.value = key.value;
var url = "/My_Servlet/response?key="+ escape(key.value);
jQuery.get(url, {}, function(data){
callback(data);}
, "text" );
}
function callback(data){
var decimal = document.getElementById('decimal');
decimal.value = data;
clear();
}
Thanks Everyone for the help. I'll vote you up.