I'm new to Dojo and having a hard time with the following piece of code. I don't understand why the chartData is empty at the very end. I created this method based on an example on the Dojo site.
The code is the following:
function(xhr, json, arrayUtil, number, Chart, theme) {
var chartData = [];
var def = xhr.get({
url: "cpuusage.json",
handleAs: "json"
});
def.then(function(res){
var data = [];
arrayUtil.forEach(res.chart, function(chart){
data[chart.x] = number.parse(chart.y);
});
chartData = data;
console.info("chartData1: ", chartData);
}, function(err){
console.error("Failed to load JSON data");
});
The first console.info within def.then says that the chartData has the correct value. When I however print the value of chartData after the def.then method finished, it's empty.
How can I make sure that chartData has the same value in and after the def.then call. Many thanks
the, methods in the xhr are all async by nature, but they return a promise. if you want to execute some code after the xhr method it should look like this:
function(xhr, json, arrayUtil, number, Chart, theme) {
var chartData = [];
xhr.get({
url: "cpuusage.json",
handleAs: "json",
load: function(jsonData) {
arrayUtil.forEach(jsonData.chart, function(chart){
chartData[chart.x] = number.parse(chart.y);
});
console.info("JSON loaded from server: ", chartData);
},
error: function() {
console.error("Failed to load JSON data");
}
}).then(function(jsonData){
console.info("chartData: ", chartData);
});
by using the then function of the promise, you make sure your code executes after the AJAX call
Related
I'm using cypress to test my VueJS application. The one thing I'm having trouble with is mocking an image to be displayed on the page. For my use case, I'm simply loading a user profile with the following code:
describe('Test Login', () => {
it('Can Login', () => {
cy.server();
cy.route({
method: 'GET',
url: '/api/account/',
response: 'fx:profile.json',
});
cy.route('**/media/demo1.png', 'fx:demo1.png');
});
});
fixtures/profile.json
{
"avatar": "http://localhost:8080/media/demo1.png",
"username": "cypress",
"email": "email#cypress.io",
"pk": 1,
"is_staff": true,
"is_superuser": true,
"is_active": true
}
The profile fixture data is loading correctly in the test. In my fixtures folder, I also have a demo1.png file. I am expecting this image to be loaded and displayed on the page during my test, but it is being displayed as a broken image.
In the network tab, it shows demo1.png as a broken image with a 200 response code and type of text/html.
The cypress documentation mostly discusses images in the context of uploading images, but I haven't been able to find an example of how I can mock an image that is loaded through a <img> tag. Is there an easier way of doing this?
I am not sure if this answer can help you. But at least it is a workaround for this problem ;-)
Say we have a HTML like this:
<html>
<body>
<button id="button">load</button>
<div id="profile">
</div>
<script>
function httpGetAsync(theUrl, callback)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
callback(JSON.parse(xmlHttp.responseText));
}
xmlHttp.open("GET", theUrl, true); // true for asynchronous
xmlHttp.send(null);
}
document.getElementById("button").addEventListener("click", () => {
httpGetAsync("/api/account/", (result) => {
var div = document.querySelector("#profile");
var img = document.createElement("img");
img.src = result.avatar;
div.appendChild(img)
})
})
</script>
</body>
</html>
source: HTTP GET request in JavaScript?
And you want to load the profile after the click was done. Then you can use MutationObserver to replace the img.src.
First, write the MutationObserver:
var observeDOM = (function(){
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
return function( obj, callback ){
if( !obj || !obj.nodeType === 1 ) return; // validation
if( MutationObserver ){
// define a new observer
var obs = new MutationObserver(function(mutations, observer){
callback(mutations);
})
// have the observer observe foo for changes in children
obs.observe( obj, { childList:true, subtree:true });
}
else if( window.addEventListener ){
obj.addEventListener('DOMNodeInserted', callback, false);
obj.addEventListener('DOMNodeRemoved', callback, false);
}
}
})();
(heavily copy & pasted from Detect changes in the DOM)
Now you are able to do this:
describe('Test Login', () => {
it('Can Login', () => {
var win = null;
cy.server();
cy.route({
method: 'GET',
url: '/api/account/',
response: 'fx:profile.json'
});
cy.visit("index.html").then(w => {
cy.get("#profile").then(pro => {
var e = pro[0];
observeDOM(e, (m) => {
// add a red dot image
m[0].addedNodes[0].src = "data:image/png;base64,"+
"iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP"+
"C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA"+
"AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J"+
"REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq"+
"ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0"+
"vr4MkhoXe0rZigAAAABJRU5ErkJggg=="
})
})
cy.get("button").click()
})
});
});
(yeah at least some lines of code are written on my own ;-P)
You can read the image from the img.src attribute from the fixtures folder. For the sake of simplicity I have used a static base64 string here.
And the result:
We are not using this kind of stuff in our aurelia app but I tried similar things in a private project some time ago.
I'm trying to use Meteor.call() and pass two variables in to complete the method
Template.RegisterForm.events({
'submit form': function(event) {
event.preventDefault();
var emailVar = event.target.registerEmail.value;
var passwordVar = event.target.registerPassword.value;
Meteor.call('registerUser', emailVar, passwordVar )
}
});
However when I call the method, emailVar and passwordVar do not pass through.
registerUser: function (email, password) {
var id = Accounts.createUser({
email: email,
password: password
});
}
they come up undefined??
You're calling the Meteor method fine,
var emailVar = event.target.registerEmail.value;
var passwordVar = event.target.registerPassword.value;
is likely your problematic code. event.target refers to the DOM element that initiated the event, in this case being the form. In turn, registerEmail and registerPassword will be undefined
See
https://jsfiddle.net/fqp3a1mq/ for an overview on using jQuery to grab your form data.
In the context of your specific issue, a clean solution is:
Template.form.events({
'submit form'(event) {
const $form = $(event.target);
const formData = $form.serializeArray();
const params = {};
event.preventDefault();
// loop over our form data and create a params object for our method
formData.forEach(data => {
params[data.name] = data.value;
});
Meteor.call('methodName', params);
},
});
Meteor.methods({
methodName(params) {
...
},
});
With this approach, if you have an input named registerEmail, then it will exist as params.registerEmail in your Meteor method.
Hope this helps.
I have a SqlDataAdapter and I want to store it in a JsonStore collection in MobileFirst and Display it in table form. I have tried using Load() method but its not working.
this is my resultSetCollection.js file
;(function () {
WL.JSONStore.init({
resultSet : {
searchFields: {"EMP_NAME":"string","EMP_ID":"integer"}
}
}, {
// password : 'PleaseChangeThisPassword'
})
.then(function () {
return WL.Client.invokeProcedure({
adapter : 'EmployeeList',
procedure : 'getEmployeeLists',
parameters : []
});
})
.then(function (responseFromAdapter) {
alert('responseFromAdapter:' + JSON.stringify(responseFromAdapter.invocationResult.resultSet));
var accessor = WL.JSONStore.get('resultSet');
var data=responseFromAdapter.invocationResult.resultSet;
var changeOptions = {
replaceCriteria : ['EMP_ID', 'EMP_NAME'],
addNew : true,
markDirty : false
};
return accessor.change(data, changeOptions);
})
.then(function (response) {
console.log(response);
//Here I want to retrieve the collection and display it in a table
})
.fail(function (errObj) {
WL.Logger.ctx({pretty: true}).error(errObj);
});
}());
An adapter procedure request from a client application will have a response object in its success and failure callbacks. So lets assume that the request was successfull and data was returned from the backend server.
Lets also assume you have a JSONStore initialized and properly setup with a collection. You then only need to get the collection and add data to it.
The below example takes the full response from an HTTP adapter request and puts it as-is into a collection. You will of course need to create a better setup for your specific scenario...
Note that the code is not optimised and performance or with 100% proper logic. It's just a demonstration flow.
Tested in MobileFirst Platform Foundation 7.0.0.00.
main.js:
var collectionName = 'mydata';
var collections = {
mydata : {
searchFields : {data: 'string'},
}
};
function wlCommonInit(){
WL.JSONStore.init(collections).then(
function() {
var resourceRequest = new WLResourceRequest("/adapters/myadapter/getStories", WLResourceRequest.GET);
resourceRequest.send().then(resourceRequestSuccess, resourceRequestFailure);
}
);
}
function resourceRequestSuccess(response) {
WL.JSONStore.get(collectionName).add(response).then(
function(){
WL.Logger.info("successfully added response to collection");
displayDataFromCollection();
},
function() {
alert("failed adding response to collection");
}
);
}
function resourceRequestFailure() {
alert ("failure");
}
If you then like to fetch the data from the JSONStore and display it in the HTML, you could do something like this:
// get a specific item from the stored response and display it in a table
function displayDataFromCollection() {
WL.JSONStore.get(collectionName).findAll().then(
function(result) {
$("#mytable").append("<tr><td>" + result[0].json.responseJSON.rss.channel.title + "</td></tr>");
},
function() {
alert ("unable to display collection");
}
);
}
The index.html looks like this:
<table id="mytable">
</table>
I have the following code which does not post data as expected
var casper = require('casper').create();
var myData;
var utils = require('utils');
casper.start();
casper.then(function () {
myData = {"source":"casperjs"};
utils.dump(myData);
});
casper.thenOpen('http://my-api/api/upload/', {
method: "post",
data: JSON.stringify(myData),
headers: {
"Content-Type":"application/json"
}
}, function () {
utils.dump(myData);
});
casper.run();
The message was sent to my server but without valid data. However, if I move the thenOpen(...) into the then(...) like this
casper.then(function () {
myData = {"source":"casperjs"};
utils.dump(myData);
this.thenOpen('http://my-api/api/upload/', {
method: "post",
data: JSON.stringify(myData),
headers: {
"Content-Type":"application/json"
}
}, function () {
utils.dump(myData);
});
});
Then the post would succeed. Or If i change the thenOpen part in the original code (i.e., without moving it in to the casper.then(...) part, like this
casper.thenOpen('http://my-api/api/upload/', {
method: "post",
data: JSON.stringify({"source":"casperjs"}),
headers: {
"Content-Type":"application/json"
}
}, function () {
utils.dump(myData);
});
Then the post would also be successful. So it looks like myData has to be initialized when the thenOpen(...) is seen. So is this expected or I have done something wrong? I could not find reference about this behavior. Thanks!
This is expected behavior as casperjs schedules the steps before running them. This means for your first listing that JSON.stringify(undefinded) will be sent to the server. The reason is that your first casper.then block was not yet executed when the object is evaluated for your casper.thenOpen block. Therefore your data was not yet assigned properly to myData, which happens inside the step.
The evaluation of the POST data on the other hand is done for the thenOpen call and not inside, so it is executed synchronously.
You already provided some good alternatives.
I have gone through as many questions on here as I could find and tried all the different suggestions and cannot get this to work. I have a view that is bound with Knockout using the mapping plugin and it works okay but only when I do the "wrong thing". Everything that I have read says that you should only make one call to ko.applyBindings() per view and then everything should update using ko.mapping.fromJS(). I cannot seem to get this to work, the only way I have been able to get my view to refresh is to call ko.applyBindings() again in the success call back from my .ajax() call. Here is the offending code.
<script type="text/javascript">
var viewModel;
$(document).ready(function() {
$("#panelbar").kendoPanelBar({
expandMode: "multiple"
});
$.ajax({
type: 'GET',
url: '/Home/IsUserMarketingManager',
success: function (data) {
if (data == true) {
$('#submitNewCase').hide();
$('#approveCase').show();
$('#disapproveCase').show();
}
}
});
// Generate client View Model from Server View Model
viewModel = new ViewModel();
ko.mapping.fromJS(#Html.Raw(Json.Encode(Model)),{}, viewModel);
ko.applyBindings(viewModel);
});
function ViewModel () {
var self = this;
self.addLocation = function() {
self.AdditionalLocations.push({ GaNumber: "" });
};
}
</script>
And later this to update the form with retrieved data:
<script type="text/javascript">
$('#btnImport').click(function () {
$.blockUI({ message: '<h2>Importing Client Information...</h2> <img src="/Images/ajax-loader.gif"><br />' });
$.ajax({
type: 'post',
url: '/Home/ImportClientCrmInfoJson',
dataType: "json",
data: ko.mapping.toJS(viewModel),
success: function (data) {
$.unblockUI();
if (!data.AccountNull) {
ko.mapping.fromJS(data, {}, viewModel);
} else {
alert("Could not find account for this GA Number, please try again.");
}
}
});
});
</script>
When submitting the form to my controller, all the data is there and mapped correctly to my server side View Model, but the form in the view isn't updated with the data that comes back from the $.ajax call. I've gotten the form to update if I do the following, but I know it's not the right way and has caused me other issues as well.
<script type="text/javascript">
$('#btnImport').click(function () {
$.blockUI({ message: '<h2>Importing Client Information...</h2> <img src="/Images/ajax-loader.gif"><br />' });
$.ajax({
type: 'post',
url: '/Home/ImportClientCrmInfoJson',
dataType: "json",
data: ko.mapping.toJS(viewModel),
success: function (data) {
$.unblockUI();
if (!data.AccountNull) {
viewModel = ko.mapping.fromJS(data);
ko.applyBindings(viewModel); // This works but isn't the right way...
} else {
alert("Could not find account for this GA Number, please try again.");
}
}
});
});
</script>
Any help would be much appreciated.
Have you examined that the following line of code appears to create a 'NEW' viewmodel?
viewModel = ko.mapping.fromJS(data);
When you do this the new viewModel the old bindings are destroyed. This is why you have to call ApplyBindings again. Anyway, I think the above line of code is the root of the problem.
Is there a way for you to create an observable property on the viewModel and allow the viewModel to reflect the data in this object? That may be a more practical approach to the update process.
In the success callback of the ajax call, use this method ko.applyBindings(viewModel) but pass as a second parameter the DOM portion you want to update as follows
ko.applyBindings(viewModel, $("#mydiv")[0])
Don't use a jquery object but a REAL DOM object.