I know there are already lots of posts out there covering this, but I'm not that good at Javascript at baseline, and most of the ones that should probably make sense use an older syntax that is confusing me.
Here is my function that I want to work:
function getUpdateForm() {
$.ajax({
url: 'test_response.html',
type: 'GET',
dataType: 'json',
success: function(data) {
$("#Form_div").html(data);
},
});
};
This is my response file:
<html>
<head>
<title>Test Response</title>
</head>
<body>
<h1>Test Page</h1>
</body>
</html>
And this is my QUnit test:
QUnit.test('getUpdateForm ajax request', function(assert) {
$.ajax = function(request) {
assert.equal(
request.url,
'test_response.html',
'request url is correct'
);
assert.equal(request.type, 'GET',
'request type is correct'
);
assert.equal(request.dataType, 'json',
'request dataType is correct'
);
};
getUpdateForm();
setTimeout(function() {
assert.equal($("#Form_div").html(), '',// not exactly sure what to put
'Received correct html in response'
);
assert.async();
}, 1000);
});
Currently it doesn't even attempt to run the assert.equal in the setTimeout function.
Please give as many details details as possible, and I will probably have many questions. First one being, how does test even get the correct function from $.ajax = function(request)?
I see what you're trying to do... but there is a tool to mock out Ajax requests for just this purpose! (Which I am the maintainer of, but still...)
Basically, in your test (or a beforeEach hook) you create a mock based on your real Ajax call, then do your code test.
First, I would start by adding a callback in your source code function so we know when the ajax call is done in the test:
function getUpdateForm(doneFunction) {
$.ajax({
url: 'test_response.html',
type: 'GET',
dataType: 'json',
success: function(data) {
$("#Form_div").html(data);
},
complete: doneFunction // <-- this is new!
});
};
Now set up your test with a mock, and execute assertions...
QUnit.test('getUpdateForm ajax request', function(assert) {
let done = assert.async(); // set up an async test
$.mockjax({
url: "test_response.html",
responseText: "<h1>Test Page</h1>"
});
getUpdateForm(function() { // this is our callback function
// now do your assertions on the content in the form div...
assert.equal($("#Form_div h1").text(), 'Test Page', 'Received correct title in html response');
done(); // then tell QUnit you are done testing.
});
});
Don't forget to include the Mockjax JS file in addition to the QUnit JS file!
Related
I'm using Vue.js to modify my DOM. I'm triggering the fetch_data() method which trying to update data.messages to read 'Love the Vue.JS' after the successful completion of the AJAX call.
The AJAX call is working successfully and it does indeed update data.message in this line:
self.message = 'Love the Vue.JS'
I can see it works because it prints in the console. The problem is that the DOM is not updating with the new definition of data.message. How do I get this to work and update the DOM when the data is updated?
var app = new Vue({
delimiters: ['[[', ']]'],
el: '#app',
data: { message: 'Hello Vue.js!' },
methods: {
fetch_data: function() {
console.log('Running script for ajax...');
$("#retrieve_data_wait").text("Retrieving data. This will update when complete...");
$.ajax({
url: '/test_json',
dataType: 'json',
timeout: 60000,
success: function(data) {
$("#retrieve_data_wait").text(data.test);
self.message = 'Love the Vue.JS';
console.log('SUCCESS')
console.log(self.message);
},
error: function(data) {
$("#retrieve_data_wait").text("Fail");
}
// error: function(jqXHR, status, errorThrown) {
// //the status returned will be "timeout"
// alert('Got an error (or reached time out) for data generation. Please refresh page and try again. If you see this more than once, please contact your customer success agent.');
// }
});
}
}
})
<div id="app">
<span id="retrieve_data_wait"></span>
</div>
The problem is that your this context gets lost when you call out to jQuery. The callback method you have (success: function) doesn't have a reference back to Vue. The way to pass the correct context is, conveniently enough, the context property in your $.ajax call.
It's all documented at the jQuery site: https://api.jquery.com/jQuery.ajax/ - just search for the word "context" and you'll find it.
Your improved ajax call should look something like this:
$.ajax({
url: '/test_json',
context: this,
// [... etc ...]
success: function(data) {
this.message = "reference to Vue data message";
}
);
You can just bind the ajax call to the parent component Vue, by adding bind(this) at the end of the ajax success sentence. It would look like the following (I have updated, I realized I had a flaw, now it should work):
$.ajax({
url: '/test_json',
// etc.
//... etc.
success: function(data) {
this.message = "reference to Vue data message";
}bind(this),
);
I'm trying to load JSON with a JS function, and then make the JSON objects that are loaded available to other functions in the same namespace. I've tried using return to serve up the array of objects retrieved, but that doesn't work. In the attached example, I've assigned the array of objects to a property in the namespaced object, but when I try to get that array of objects outside the main loadData function, all I get is null.
Here's my JS:
var myObj = {
jsonEndPoint: '/test/test.json',
dataObjects: null
}
myObj.loadData = function () {
$.ajax({
url: 'test.json',
type: 'POST',
dataType: 'json',
success: function (data) {
myObj.dataObjects = data.apiResults[0].league.season.draft.rounds[0].picks;
//console.log(myObj.dataObjects);
},
error: function (xhr, textStatus, errorThrown) {
console.log('Data Load Error: ' + textStatus);
}
});
}()
myObj.displayData = function() {
console.log(myObj.dataObjects)
}()
The full example can be seen here: http://zbl.me/test/index.html
The JSON file I'm loading is here: http://zbl.me/test/test.json
That is because JavaScript is asynchronous in nature — when you attempt to access the myObj.dataObjects in the myObj.displayData function, that object does not yet exist because the AJAX call has not been completed yet.
What you could do is that ensure that all functions that require newly added data from the AJAX call be run only when a .done() promise has been delivered from your AJAX call, by using $.when(). The logic is quite straightforward:
myObj.loadData() is now exclusively used to make the AJAX call. With regards to how we handle the done and fail events (which are previously .success() and .error() callbacks), we delegate that logic to the next function.
myObj.displayData() is now use to evaluate the promise returned by your AJAX call made with myObj.loadData(). You use $.when() to fetch the promise, and then simply chain .done() to deal with a successful call and .fail() to deal with the opposite :)
Here's your improved code:
var myObj = {
jsonEndPoint: '/test/test.json',
dataObjects: null
}
myObj.loadData = function () {
// We return the AJAX object so that we can evaluate the state later
// This is very simple :)
return $.ajax({
url: 'test.json',
type: 'POST',
dataType: 'json'
});
}()
myObj.displayData = function() {
// Instead of using the deprecated .success() and .error()
// ... we use .done() and .fail()
$.when(myObj.loadData).done(function(data) {
myObj.dataObjects = data.apiResults[0].league.season.draft.rounds[0].picks;
}).fail(function(xhr, textStatus, errorThrown) {
console.log('Data Load Error: ' + textStatus);
});
}()
If you are unsure, you can check the dummy code here: http://jsfiddle.net/teddyrised/5rbd2eqq/1/ I have used the built-in JSON response from JSfiddle to generate an artificial response, but the logic is exactly the same as yours.
Your displayData method is called even before the ajax is completed. So you either need to call displayData in the success callback of ajax or change the structure a bit so that its easy to call.
Why don't you instead do something like this
var myObj = {
jsonEndPoint: '/test/test.json',
dataObjects: null,
displayData: function() {
console.log(this.dataObjects);
},
loadData: function() {
$.ajax({
context: this,
url: 'test.json',
type: 'GET',
dataType: 'json',
success: function(data) {
this.dataObjects = data.apiResults[0].league.season.draft.rounds[0].picks;
console.log(myObj.dataObjects);
this.displayData();
},
error: function(xhr, textStatus, errorThrown) {
console.log('Data Load Error: ' + textStatus);
}
});
}
};
myObj.loadData();
Here is a demo
below is an ajax but it wont work, what seems be the problem? assume that I have requestparser.php and inside it i have "echo "yes ajax work!";".
$(document).ready(function(){
// start ajax form submission
$.ajax({
url: "requestparser.php",
type:"POST",
data: ({ "pulldata" : "oy" }),
success:function(e){
if(($.trim(e)=="success")){
alert("yes");
}else{
alert("no");
}
},error:function(){
alert("error");
}
});
});
as above ajax function ,the process should be, on load it will send first a post request to requestparser.php with a post name of "pulldata" and post content of "oy" and when the requestparser receive that post request from the ajax so then respond with "yes ajax work!" and since the respond from requestparser.php is not equal to success then it should display "no".
any help would be greatly appreciated
I tried to debug your code and it worked fine for me. So can you try this code and say what error it shows ?
$(document).ready(function () {
$.ajax({
url: "test.php",
type: "POST",
data: ({
"pulldata": "oy"
}),
success: function (e) {
console.log(e);
},
error: function (e) {
console.error(e);
}
});
});
test.php
<?php
var_dump($_POST);
One more thing, just for confirmation, you have included jQuery in your page before using ajax right ?
I am having one of those ajax asynchronous problems. I have this function which accepts two parameters to send data to the server by jquery ajax. I know this can be done by using promises and callback functions but this is my specific problem.
function fillLightbox(id, text, callback)
{
// get json request of studyunit details
$.ajax(
{
type: 'GET',
url: 'updateExam',
data:
{
get_details: true,
exam_code: text,
event_id: id
},
dataType: 'json',
success: callback
});
}
That is my ajax request, then I have this function for an API:
scheduler.createGridView(
{
name:"grid",
fields:
[
{id:"text", label:'Unit Code', sort:'str', width:200},
{id:"date", label:'Date', sort:'date', width:'*'},
{id:"exam-title", label:'Title', sort:'str', width:'*',
template: function(start, end, ev)
{
fillLightbox(ev.id, ev.text, function(data)
{
var title = data.title;
// i can get my data here..
});
return title; // how can I do this?
}
}
]
});
My question is how can I modify the template function available in this API to be able to return the property. i.e. can I somehow pass a callback function there as well?
Please do not suggest async: false (This obviously works but lags on the browser)
EDIT: more details about Create Grid View template are found here: http://docs.dhtmlx.com/scheduler/grid_view.html#datatemplates
Thanks for your help
I want to perform an action write to file in controllers/static_pages_controller.rb:
def fileopen
my_file = File.new("public/CHNAME1.txt","w")
my_file.write "\tfasf"
my_file.close
end
(it work well when i define it in helper and call it in view.)
in myview.html.erb, i want some thing like How can I do that? I tried in application.js
function readfile() {
alert('readfile work')
$.ajax({
alert('ajax work')
url: "/fileopen",
type: "POST",
##don't know what to to to call fileopen
}
});
}
routes.rb
match '/fileopen', to:'static_pages#fileopen', via: 'get'
and it's seem nothing happen. Only the first alert work
You have syntax error, try this:
function readfile() {
alert('readfile work');
$.ajax({
url: "/fileopen",
type: "POST",
success: function(){
alert('ajax work');
}
});
}
I don't know ruby but route is on "GET" request and you are making "POST" request:
match '/fileopen', to:'static_pages#fileopen', via: 'get' // should be via: 'post'?
You can not use alert within ajax, If you want to use it then use in success and error methods