$.ajax responseText differs from responseJSON - javascript

I am seeing a difference in what is returned when comparing the responseJSON and responseText properties of my ajax request.
In the image below, you see that referencing the responseJSON excludes the "properties" property. When I parse and use the responseText, the "properties" property is included.
I've not encountered this kind of weirdness before, anyone have any suggestions or thoughts as to why this is occurring?
Edit 1: The properties object is undefined when attempting to access it directly from the responseJSON. See below image:
Edit 2: I am unable to replicate this issue in my jsFiddle (http://jsfiddle.net/madChemist/4hd9cz1g/). I am using jQuery version 2.1.4 incase that helps to diagnose things.
The responseJSON is equivalent to the parsed responseText in my fiddle:
Parsed responseText properties - {"border-color":"cyan","border-style":"dashed","border-width":"5px"}
Unoutched responseJSON properties - {"border-color":"cyan","border-style":"dashed","border-width":"5px"}
The two differences I see between my environment and this one are primarily that the ajax request type is a GET not POST. The data in the fiddle was trimmed compared to what I am loading in my environment. I tested both trimmed & untrimmed which produced no difference in my findings.
Edit 3: I've taken some screenshots of my code to demonstrate what I am attempting to do. The screenshots I took originally were logged while I had my breakpoint on the second assertion in the unit test module.

My tests are passing now. My issue may actually be with QUnit's scoping. The odd behavior above went away when I made these changes to my test:
QUnit.test("Method exportLayout", 2, function (assert) {
var done = assert.async();
$('body').append('<div id="application" style="display:none;"></div>');
var controller = new ApplicationController();
controller.createApplicationWorkspace();
var load = controller.loadLocalProject(); // Pulls in local JSON file
load.complete(function (request) {
var loaded = request.responseJSON; //$.parseJSON(request.responseText);
controller.setUpLayout($.parseJSON(request.responseText)); // Creates workspace from saved state
var result = controller.generateLayout(); // Generates Object. Data property should equal what was loaded in originally.
assert.ok(result !== undefined && result.data !== undefined, "Application controller generates layout response in a proper format.");
assert.deepEqual(loaded, result.data, "Freshly generated export is the same as initially loaded in import.");
// Teardown
setTimeout(function () {
controller.layout.destroy();
$('#application').remove();
done();
}, 0);
});
});
Specifically made this change:
controller.setUpLayout($.parseJSON(request.responseText));
The setUpLayout method is a few hundred lines long, but this is how it begins:
setUpLayout: function (loaded) {
if (typeof loaded !== 'object' || !loaded.hasOwnProperty('rows')) {
throw new Error('Invalid format for loaded paramater in setUpLayout method.');
}
var initial_mode = TE.Application.reqres.request('editor:mode');
TE.Application.vent.trigger('editor:toggle_mode', true);
var layout = $.extend({}, loaded);
var rowCollection = this.layout.editor.currentView.rows.currentView;
var rows = layout.rows; // Once stashed in a var,
...
// Doesn't make use of `loaded` parameter. Only modifications are to `layout` variable.
}
I feel like there may still be something else at work here, but I wanted to update this post with what I had just found. Hoping someone else may be able to notice something that I did not.

Related

Rally SDK collection store sync throwing 404

EDIT: I ended up using Rally.data.util.Record.serverSideCopy() and re-retrieving/updating the new testcase to finish this work up. I'm leaving this unresolved as I still can't figure out why I was getting the 404 on sync (though, I'll likely not have time to dig into it since I went in a different direction).
I'm attempting to add TestCaseSteps to a TestCase (which I copied from another TestCase - original collection of steps was lost during the save as they were associated with the original TestCase). I tried following the add/sync pattern suggested in the Collection Modification section of the doc , but supplying only the _ref value of the Steps caused the sync() operation to fail with a 404 on the POST:
HTTP ERROR 404
Problem accessing /slm/webservice/v2.0/TestCase/90167266916/Steps/add. Reason:
Not Found
As seen below, I then attempted to add the Steps via raw objects instead of _ref values, but I received the same 404.
What am I doing wrong here? Why are my sync operations resulting in a 404?
For further context, here's the repo:
https://github.com/crdschurch/reuse-rally-test
var newSteps = newTestCase.getCollection('Steps', {autoLoad: true});
oldTestCase.getCollection('Steps').load({
callback: function(oldRecords, newOperation, newSuccess) {
Ext.Array.each(oldRecords, function(step) {
console.log(step.get('_ref'));
//debugger;
newSteps.add(
{
'Input': step.get('Input'),
'ExpectedResult': step.get('ExpectedResult'),
'StepIndex': step.get('StepIndex'),
'TestCase': newTestCase.get('ObjectID')
}
);
});
console.log('Syncing: ');
console.log(newSteps);
newSteps.sync({
callback: function() {
console.log('New Test: ');
console.log(newTestCase);
}
});
}
});
My guess is that you need to specify TestCase as a ref rather than just its objectid:
newSteps.add({
'Input': step.get('Input'),
'ExpectedResult': step.get('ExpectedResult'),
'StepIndex': step.get('StepIndex'),
'TestCase': newTestCase.get('_ref')
});

uncaught TypeError: undefined is not a function when using JSON object with name

I'm using D3js with Mongodb and AnguarlJS to display my data. All is good that it works until when I give my JSON array a name. Then angular starts complaining about stuff and I'm not sure why.
this is the original json array that works with this original code
[
{
"defaultCategory":"Happy",
"timesUsed":2704659
},
{
"defaultCategory":"Sad",
"timesUsed":4499890
},
{
"defaultCategory":"Laughter",
"timesUsed":2159981
},
{
"defaultCategory":"Smirk",
"timesUsed":3853788
},
{
"defaultCategory":"Flirty",
"timesUsed":14106543
}
]
d3.json("data.json", function(error, data) {
data.forEach(function(d) {
d.timesUsed =+ d.timesUsed;
});
but when i change the json to this format, it breaks
{
"mymood":[
{
"defaultCategory":"Happy",
"timesUsed":2704659
},
{
"defaultCategory":"Sad",
"timesUsed":4499890
},
{
"defaultCategory":"Laughter",
"timesUsed":2159981
},
{
"defaultCategory":"Smirk",
"timesUsed":3853788
},
{
"defaultCategory":"Flirty",
"timesUsed":14106543
}
]
}
d3.json("data.json", function(error, data) {
data.mymood.forEach(function(d) {
d.timesUsed =+ d.timesUsed;
});
In the chrome console the error is happening at the line data.mymood.foreach line,
but i dont understand why because its exactly returning the same json as if there was no name like this
[object, object, object,object,object]
and the parameter d in the function also returns the same object within the array
edit
Error:
Uncaught TypeError: undefined is not a function
console.log(data) -> Object {mymood: Array[5]}
console.log(data.mymood) -> [Object, Object, Object, Object, Object]
gist for those who are interested in the full code
https://gist.github.com/gwong89/e3a29b64d94ad20256bb
Like Oscar had pointed out, the forEach loop works fine. However, after look closely at your gist, if you try to use the mymood key, make sure you also change line 55 where you were using
var g = svg.selectAll('g')
.data(pie(data))
to
var g = svg.selectAll('g')
.data(pie(data.mymood))
Also on line 76 where you had
var total = d3.sum(data.map(function(d) {
to
var total = d3.sum(data.mymood.map(function(d) {
I grabbed your project repo and tried these out on my local environment, and I can render the pie chart and popup without seeing any errors.
Your code seems to be working fine (from what I've tested). I will suggest to try debugging your code or if you feel more comfortable try doing many console.log(...) as possible and keep checking your browser console from the beginning (I have nothing else to say). Try to also use Developer Tools from Chrome which is a better option.
I've tried to replicate your context by using d3.js library and uploaded a json file with your data to my Dropbox just to be able to perform an ajax request and everything is fine again (also new JSON structure is valid). Here's what I did, probably could help you to learn something new (see below).
Possible hints/suggestions to fix your issue:
According to the question title, it seems that data.mymood is undefined so you are not able to do a forEach of something that doesn't exist. Try validating things and avoid null pointers (see example).
JSON structures are valid so that's not the problem.
Syntax seems to be valid from what I've tested.
Check if there's a conflict between libraries, try to do some research about using all the libraries needed together (not sure if this is your situation but could happen).
Check your browser console and do some debugging as the first paragraph says.
Check if your request is not timing out or something else is happening, check the Network tab or log your requests in browser console using Developer Tools from Chrome (just saying).
Live Demo: http://jsfiddle.net/29f6n8L7/
d3.json('https://dl.dropboxusercontent.com/u/15208254/stackoverflow/data.json', function(data) {
// Some ways to avoid null pointers
var obj = (data || {}), // If 'data' is null, initialize as an Object
moods = (obj.mymood || []), // If 'obj.mymood' is null, initialize as an Array
time = 0,
mood;
// Same way to get 'mymood' from the object
console.log('Your obj.mymood contains: %o', obj.mymood);
console.log('Your obj["mymood"] contains: %o', obj['mymood']);
/**
* I will suggest to use a traditional loop instead of 'forEach'.
* Please read: http://stackoverflow.com/a/9329476/1178686
* for a better explanation
*/
for (var i = 0; i < moods.length; ++i) {
mood = moods[i];
if (mood) {
time += mood.timesUsed;
}
}
// Output
console.log('Sum of timesUsed is: %s', time);
});
Arrays have a built in for each in es5, objects do not.

Script works in development environment, but not in production

I am running an angular app. I am having the strangest effect ever...
I am calling a backend which returns a json. I parse that json and build an object structure client side. It works perfectly in dev but the exact same code does provide strange effects on prod. See code inline comments for hints. The only thing I could think of is that the data comes different from prod...
I can't see what's wrong, as it's the exact same code, and it's driving me completely nuts, probably the worse thing I ever saw in 10+ years programming!
Basically the json structure is a list of objects, every object has a reference ID, and several objects are correlated by the same reference ID - I need a structure where I'd access all objects with the same reference ID.
Maybe I'll make a fool of myself here but I really can't see it...I just ran the data in two JSON validators and both say the data is valid.
app.factory('ItemService', ['ItemProvider', function(itemProvider) {
var itemSrv;
var obj_by_id = {}; //create empty object
itemSrv = function(callback) {
itemProvider.get_data()
.success(function(data) { // callback ok, data has json content
for (var i=0; i<data.length; i++) {
obj = data[i]; // I get the object in the json
if (! (obj.identificador in obj_by_id)) {
obj_by_id[obj.identificador] = {}; //build a key in the object if not already available
}
obj_by_id[obj.identificador][obj.campo_nombre] = obj; //assign the object by keys
console.log(obj_by_id); **//HERE obj_by_id is ALWAYS EMPTY!!!! BUT ONLY ON PROD!!! On dev works fine...**
}
callback(obj_by_id); //Here I would get the whole structure, but it's empty on prod...
})
.error(function(data) {
console.log("Error getting data from server");
});
}
//factory function body that constructs shinyNewServiceInstance
return itemSrv;
}]);
EDIT: console.log(data) right after success, on request
dev:
http://imgur.com/10aQsx2,rJJw2bb#0
prod:
http://imgur.com/10aQsx2,rJJw2bb#1
EDIT2: you can have a look at the returned data here (will remove this link later!): http://bibliolabs.cc/milfs/api.php/ison?id=2
I am concerned about all those \u unicode chars, could that be an issue?

Passing objects from NodeJS to client and then into KnockoutJS viewmodel

So thanks to SO I can pass an object from node to the client, but then getting it into a knockout view model is a bit awkward. These are the steps I have so far (I've included links to the relevant lines as they appear in my github project. Thought the context might help.):
Apply JSON.stringify and pass to the jade file
recipeJSON: JSON.stringify(recipe);
Wrap this in a function in a header script that just parses the JSON and returns the result
script
function getRecipeObject() {
var r = '!{recipeJSON}';
return JSON.parse(r);
}
Call this function and pass the result to a view model constructor
self.recipe = ko.observable(new Recipe(getRecipeObject()));
This works but is there a better way?
Question clarification (Edit): I feel step 2 shouldn't be necessary. Is there a way to directly pass the JSON from node to the Recipe() constructor, without the getRecipeObject() acting as an intermediate step? I tried passing recipeJSON in directly like so
self.recipe = ko.observable(JSON.parse('!{recipeJSON}'));
That doesn't work I think because its not a jade template and has no access to the variable.
According to the answer to this question rendering data into scripts is bad practice and I should instead make an XHR call on page load instead.
Edit
I just saw you linked a github repo! So you're already familiar with most of this...you even have an endpoint set up at /recipe/:id/view, so now I'm really confused...what isn't working out for you? Just the last step of deserialization using ko.utils.*?
Sorry about all the exposition -- I thought this was way more rudimentary than it actually was; I hope no offense taken there!
You really don't want to return a script to execute -- instead, treat this as a DTO: an object that just stores data (no behaviors). An example would be:
{
recipeID: 12,
reviewIDs: [42, 12, 55, 31],
rating: 4.2
recipeName: "A super tasty pie!"
}
This object (representation) is a projection -- a simplified version of the full data stored in the database.
The next step is to create an endpoint to access that data on the server. Let's assume you're using Express:
var app = express();
app.get('/recipes/:recipeID', function(req, res) {
var recipeID = req.params.recipeID;
// It would be cool if this existed, huh?
getRecipeAsync(recipeID, function(recipe) {
res.status(200).json(recipe);
});
});
If you send a GET request to your (hypothetical) application (let's say it's https://localhost:8080/recipes/12), you'll get json representing the (admittedly imaginary) recipe with ID 12.
You can accomplish getting the JSON with jQuery (or any other library that makes XHR nice and pretty)
var recipeID = 12;
$.ajax({
url: "/recipes/" + recipeID,
type: "GET"
}).then(function(recipe) {
console.log("Hey! I got the recipe: %O", recipe);
// Note: you might need to use ko.utils.fromJS(recipe) if the returned
// data is JSON that ISN'T deserialized into an object
var recipeObservable = ko.utils.fromJS(recipe);
});
That's about everything you need to know. Obviously, the devil's in the details, but that's basic idea; let me know if that helps!

webOS/Ares : read JSON from URL, assign to label

I've used the webOS Ares tool to create a relatively simple App. It displays an image and underneath the image are two labels. One is static, and the other label should be updated with new information by tapping the image.
When I tap the image, I wish to obtain a JSON object via a URL (http://jonathanstark.com/card/api/latest). The typcial JSON that is returned looks like this:
{"balance":{"amount":"0","amount_formatted":"$0.00","balance_id":"28087","created_at":"2011-08-09T12:17:02-0700","message":"My balance is $0.00 as of Aug 9th at 3:17pm EDT (America\/New_York)"}}
I want to parse the JSON's "amount_formatted" field and assign the result to the dynamic label (called cardBalance in main-chrome.js). I know that the JSON should return a single object, per the API.
If that goes well, I will create an additional label and convert/assign the "created_at" field to an additional label, but I want to walk before I run.
I'm having some trouble using AJAX to get the JSON, parse the JSON, and assign a string to one of the labels.
After I get this working, I plan to see if I can load this result on the application's load instead of first requiring the user to tap.
So far, this is my code in the main-assistant.js file. jCard is the image.
Code:
function MainAssistant(argFromPusher) {}
MainAssistant.prototype = {
setup: function() {
Ares.setupSceneAssistant(this);
},
cleanup: function() {
Ares.cleanupSceneAssistant(this);
},
giveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
},
jcardImageTap: function(inSender, event) {
//get "amount_formatted" in JSON from http://jonathanstark.com/card/api/latest
//and assign it to the "updatedBalance" label.
// I need to use Ajax.Request here.
Mojo.Log.info("Requesting latest card balance from Jonathan's Card");
var balanceRequest = new Ajax.Request("http://jonathanstark.com/card/api/latest", {
method: 'get',
evalJSON: 'false',
onSuccess: this.balanceRequestSuccess.bind(this),
onFailure: this.balanceRequestFailure.bind(this)
});
//After I can get the balance working, also get "created_at", parse it, and reformat it in the local time prefs.
},
//Test
balanceRequestSuccess: function(balanceResponse) {
//Chrome says that the page is returning X-JSON.
balanceJSON = balanceResponse.headerJSON;
var balanceAmtFromWeb = balanceJSON.getElementsByTagName("amount_formatted");
Mojo.Log.info(balanceAmtFromWeb[0]);
//The label I wish to update is named "updatedBalance" in main-chrome.js
updatedBalance.label = balanceAmtFromWeb[0];
},
balanceRequestFailure: function(balanceResponse) {
Mojo.Log.info("Failed to get the card balance: " + balanceResponse.getAllHeaders());
Mojo.Log.info(balanceResponse.responseText);
Mojo.Controller.errorDialog("Failed to load the latest card balance.");
},
//End test
btnGiveCoffeeTap: function(inSender, event) {
window.location = "http://jonathanstark.com/card/#give-a-coffee";
}
};
Here is a screenshot of the application running in the Chrome browser:
In the browser, I get some additional errors that weren't present in the Ares log viewer:
XMLHttpRequest cannot load http://jonathanstark.com/card/api/latest. Origin https://ares.palm.com is not allowed by Access-Control-Allow-Origin.
and
Refused to get unsafe header "X-JSON"
Any assistance is appreciated.
Ajax is the right tool for the job. Since webOS comes packaged with the Prototype library, try using it's Ajax.Request function to do the job. To see some examples of it, you can check out the source code to a webOS app I wrote, Plogger, that accesses Blogger on webOS using Ajax calls. In particular, the source for my post-list-assistant is probably the cleanest to look at to get the idea.
Ajax is pretty much the way you want to get data, even if it sometimes feels like overkill, since it's one of the few ways you can get asynchronous behavior in JavaScript. Otherwise you'd end up with code that hangs the interface while waiting on a response from a server (JavaScript is single threaded).

Categories

Resources