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),
);
Related
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!
I've been working with ajax to get input values from a form when it's submitted, but when I look into the console it comes back as 0. I'm not too familiar with ajax overall, so I'm not sure if I'm not using this correctly or if I have an error somewhere else.
Here's what I have:
JS:
jQuery(this).find(".form-item").on("submit", function(e) {
var $this = jQuery(this);
if (this.checkValidity()) {
e.preventDefault();
$.ajax({
url: Config.ajaxurl,
type: 'POST',
dataType: 'json',
accepts: 'application/json',
context: this,
data: {
action: 'process_form',
form_info: {
"input_18_16": $(this).parents('.form-item').find('#input_18_16').val() || '',
"input_18_17": $(this).parents('.form-item').find('#input_18_17').val() || '',
"input_18_3": $(this).parents('.form-item').find('#input_18_3').val() || '',
"input_18_2": $(this).parents('.form-item').find('#input_18_2').val() || ''
},
},
success: function(data, status, xhr) {
console.log('Response:\n', data)
console.log('successful trigger');
console.log($(this).find('#input_18_16').val());
},
error: function(xhr, code, error) {
console.log(error)
}
})
}
});
The crazy thing is that I can get the data correctly from this:
console.log($(this).find('#input_18_16').val());
In the console. Which but for some reason the console.log('Response:\n', data) comes back as Response:0 so I'm not sure why it's successful but not able to return anything?
In the success function you should use $this instead of $(this). That's why you set it in the first place, isn't it?
You can also use it in the data: option, since it's more efficient to reuse the variable instead of calling jQuery() repeatedly.
the data in 'console.log('Response:\n', data)' is actually being returned from the success function after ajax returns successful. Is is not the same as the data you are posting to Config.ajaxurl.
Check the missing ";" on the line console.log('Response:\n', data).
And I think the "\n" not affects the console.log mensage.
EGG: After this, checkout it https://api.jquery.com/serialize/ may be make your life more easy
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
I am currently developping a new website
When I am trying to create an account, I get an error like this :
Uncaught TypeError: Cannot read property 'hasError' of null.
And this is the code
function submitFunction()
{
$('#create_account_error').html('').hide();
//send the ajax request to the server
$.ajax({
type: 'POST',
url: baseUri,
async: true,
cache: false,
dataType : "json",
data: {
controller: 'authentication',
SubmitCreate: 1,
ajax: true,
email_create: $('#email_create').val(),
back: $('input[name=back]').val(),
token: token
},
success: function(jsonData)
{
if (jsonData.hasError())
{
var errors = '';
for(error in jsonData.errors)
//IE6 bug fix
if(error != 'indexOf')
errors += '<li>'+jsonData.errors[error]+'</li>';
$('#create_account_error').html('<ol>'+errors+'</ol>').show();
}
else
{
// adding a div to display a transition
$('#center_column').html('<div id="noSlide">'+$('#center_column').html()+'</div>');
$('#noSlide').fadeOut('slow', function(){
$('#noSlide').html(jsonData.page);
// update the state (when this file is called from AJAX you still need to update the state)
bindStateInputAndUpdate();
$(this).fadeIn('slow', function(){
document.location = '#account-creation';
});
});
}
},
error: function(XMLHttpRequest, textStatus, errorThrown)
{
alert("TECHNICAL ERROR: unable to load form.\n\nDetails:\nError thrown: " + XMLHttpRequest + "\n" + 'Text status: ' + textStatus);
}
});
}
It seems to be the jsonData, on the function, which is not working as well. Any idea or suggestions?
The success handler will be passed the data returned from the ajax request.
It will not have a function called hasError() because it is just a json object it will not have any functions.
The error handler should be fired if there is an http error i.e. if the ajax call returns an http 500.
I'm not familiar with prestashop, but looking over the prestashop documentation hasError is returned as a bool (not a function), so instead try (without the parenthesis).
if (jsonData.hasError)
You may also want to check if any data is returned first.
if (jsonData)
This is related to my previous question. The answer there seemed to solve the problem.
But I am literally doing the exact same thing from another route, and now I get an error. The application passes over the ajax function twice. The first time, I get a TypeError. If I reload the page, then the function executes correctly.
I know in the docs, it mentions having to create and object that is defined. Could somebody point me to an example of how extended controller needs to be created in order to execute a function when it is called.
I get an error: TypeError: this.init is undefined
Here is my route:
App.RegisterPickRoute = Em.Route.extend({
redirect: function() {
var registerTestController=this.controllerFor('registerTest')
var isRegistered=registerTestController.registerContacts();
if(!isRegistered)
this.transitionTo('registerTest');
else
alert('holla')
}
});
Here is my function in my controller:
registerContacts: function(){
var isRegistered=false;
var self=this
self.contactsToAdd=self.get('contactList').filterProperty('isSelected', true);
$.ajax({
type: 'POST',
cache: false,
url: contextPath + 'user/regTest',
data:{contactList:self.contactsToAdd},
success: function(data) {
isRegistered=true;
},
error: function(jqXHR, textStatus, errorThrown) {
isRegistered=false;
},
async: false
});
return isRegistered
}
I have a syntax error. The value passed to the data attribute of the ajax call needs to be self.contactsToAdd.toArray()