I'm fetching a JSON response and with that response, I have two values:
Air shipment cost.
Land shipment cost.
I want to save those two values somewhere in the client so that when a user chooses either 1 radio button or the other, I add that value to another element on the page.
Here's what I'm doing:
<script type="text/javascript">
$(document).ready(function () {
var landCost;
var airCost;
$("#ddlCiudad").change(function () {
var idCity = $("#ddlCiudad").val();
$.getJSON("/ProductCheckout/GetPriceForLocation", { cityId: idCity, productId: idProduct, type: "land" },
function (cityData) {
console.log("Recieved json data."); //This part works. It outputs.
var data = $.parseJSON(cityData);
console.log("Parse JSON response."); //This part works. It outputs.
landCost = data.LandCost;
console.log("Assigned value of LandCost"); //FAILS HERE. nothing is shown. not even an error.
airCost = data.AirCost;
console.log("Assigned value of AirCost");
alert(landCost);
console.log("Alerted land!");
alert(airCost);
console.log("Alerted air!");
}
);
});
So what do you suggest? I need to have the values of this JSON response, available for usage on that page, if I declare the variable inside the change() event, it'll be out of scope.
{"DaysToShip":" TER = 48 Hrs / AER = 24 Hrs","LandCost":"25,00","AirCost":""}
try
landCost = cityData.LandCost;
If you really must use global variables, you can attach them directly to the window object.
window.airCost = cityData.AirCost;
Really though you want to have the json request and the 'radio button' handling in the same scope, so that you're not polluting the global namespace at all.
Your call to $.parseJSON() is returning null because the data passed to your callback has already been parsed to JSON.
var json = {LandCost:3, AirCost:5},
results = $.parseJSON(json);
console.log(results); // results == null
IF you want to globally declare your variables, either put them outside the jQuery closure ($(document).ready(function () {...});), or don't use var to declare them. If you don't use the var keyword the variable will default to a global.
Here is a jsfiddle of setting global variables without using the var keyword: http://jsfiddle.net/jasper/JWtbV/
Have you considered using jQuery's $.data() function to attached the values directly to the body element in the DOM and accessing it from there?
// Set Values
$('body').data('landCost', data.LandCost);
$('body').data('airCost', data.AirCost);
// Retrieve Values //
console.log($('body').data('landCost');
console.log($('body').data('airCost');
Hope it helps.
Related
I am a beginner and using $.get to retrieve data from a rest API such as:
[{"id":"1","url":"http:\/\/123.456.78.910\/workforce\/images\/item1.jpg","price":"99","description":"Mobile Phone"},
{"id":"2","url":"http:\/\/123.456.78.910\/workforce\/images\/item2.jpg","price":"98","description":"Laptop"}
{"id":"3","url":"http:\/\/123.456.78.910\/workforce\/images\/item3.jpg","price":"92","description":"Console"}] }
$.get('http://xxxxxxxxxxx,
function (data) {
var obj = $.parseJSON(data);
So from what I understand I have retrieved the data from the REST API and parsed it so it is stored in a variable called obj.
My question is, how do I access and use each unique record in the obj variable?
Each record has it's own picture (item1.jpg, item2.jpg etc).
Whem my app loads I want it to show the item1.jpg image, and I want to be able to navigate to the other item pictures using buttons (previous / next).
I also want the description and price to be displayed underneath in some text input fields.
What I have figured so far is that I should:
Iterate through the obj variable, and store each record into an array.
Upon app initialisation I can set the default value for the image placeholder to array[index0].url, and set the description and price fields.
I can then set the previous and next buttons to array[currentIndex-1] or array[currentIndex+1].
Would this be the best way to do it?
Or can I just do this without using an array and manipulate the obj.data directly?
Thanks!!!
I may not be understanding what exactly what you want to do but I think I have the gist. If you just want to show the picture then the array of just images probably wouldn't be a bad idea. However, it looks like the Jason you're getting is already in an array. You can just use array index notation to get to what you want.
ie)
var arr = //your json response ;
var current = 0; //sets currently displayed object to the first in the array
var setCurrent = function () {
var image = arr[current]["url"];
}
You can then modify current however you want (on click on arrow iterate up/down, etc) then call the setCurrent function to set your image the the one you want. Hope that helps!
You can use the response you have from $.get() directly.
It is an array of objects.
You can use it like this:
console.log(data[2].description);
// outputs: "Console"
I've made a CodePen demo where it has a 4th object with a real image url to show you how to use the url info...
EDIT
Just in case you wouldn't know this:
You can use the response inside the scope of the $.get() callback...
You can not use it straith after the $.get() outside the callback since $.get() is asynchronous.
You can use it in some other handler wich will happen after the response is received.
var getResponse;
$.get('http://xxxxxxxxxxx', function (data) {
getResponse = data;
console.log(data[2].description);
// outputs: "Console"
console.log(getResponse[2].description);
// outputs: "Console"
});
console.log(getResponse[2].description);
// outputs: "Undefined"
// But since this handler will be triggered long after the response is obtained:
$("#somebutton").click(function(){
console.log(getResponse[2].description);
// outputs: "console"
});
In order for your page javascript to be able to access the data retrieved from your ajax request, you'll need to assign it to some variable which exists outside the callback function.
You will need to wait until the ajax request has been processed before you can read the array. So you might want to set the actual default image to be something that doesn't rely on the ajax request (a local image).
Here's a simple approach
// fake testing ajax func
function fakeget (url, callback) {
setTimeout(callback(JSON.stringify([
{"id":"1","url":"http:\/\/123.456.78.910\/workforce\/images\/item1.jpg","price":"99","description":"Mobile Phone"}, {"id":"2","url":"http:\/\/123.456.78.910\/workforce\/images\/item2.jpg","price":"98","description":"Laptop"},
{"id":"3","url":"http:\/\/123.456.78.910\/workforce\/images\/item3.jpg","price":"92","description":"Console"}
])), 1000);
}
// real code starts here
// global variables for ajax callback and setImg func to update
var imageData, currentImg;
// change this back to $.get for real
fakeget('http://xxxxxxxxxxx',
function (data) {
imageData = $.parseJSON(data);
setImg(0);
}
);
function setImg(index) {
// turns negative indices into expected "wraparound" index
currentImg = (index % imageData.length + imageData.length) % imageData.length;
var r = imageData[currentImg];
$("#theImg").attr('src', r.url);
$('#theDescription').text(r.price + " " + r.description);
}
$("#prev").click(function () {
setImg(currentImg - 1);
});
$("#next").click(function () {
setImg(currentImg + 1);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<img id='theImg' src='somedefault.jpg'>
<div id='theDescription'></div>
</div>
<button id='prev'>Prev</button>
<button id='next'>Next</button>
Few observations :
Your JSON Object is not a valid JSON.
No need to parse it again your data is already a JSON Object.
Working fiddle
var data = [{"id":"1","url":"http:\/\/123.456.78.910\/workforce\/images\/item1.jpg","price":"99","description":"Mobile Phone"},{"id":"2","url":"http:\/\/123.456.78.910\/workforce\/images\/item2.jpg","price":"98","description":"Laptop"}, {"id":"3","url":"http:\/\/123.456.78.910\/workforce\/images\/item3.jpg","price":"92","description":"Console"}];
for (var i in data) {
var imgUrl = data[i].url;
console.log(imgUrl);
}
I have a form which when loaded sends GET request to server and recives data which will stored in 'master' and i copy that data to 'local' as below.
$scope.dirty = false;
init(data);
function init(data) {
$scope.master = angular.copy(data.data);
$scope.local = angular.copy($scope.master);
}
Now, I use local object as model for my form and I have to button submit and reset. I watch the local object as below.
$scope.$watchCollection('local', function (newLocal, oldLocal) {
$scope.dirty = !angular.equals(newLocal, $scope.master);
});
So, If dirty is true then i can know that data has been modified but since I am using Objects AngularJS adds $$hasKey to $scope.local and because of that $scope.dirty always sets to true.
So, is there any way to handle this problem? I am new to AngularJS so may be this can be funny question but I'm stuck.
You could convert your object to a JSON string before comparing:
function init(data) {
// store json data into $scope.master for later comparison
$scope.master = angular.toJson(data.data);
$scope.local = angular.copy(data.data);
}
$scope.$watchCollection('local', function (newLocal, oldLocal) {
var json = angular.toJson(newLocal); // new local without $$ key
$scope.status.dirty = !angular.equals(json, $scope.master);
// $scope.local is still a javascript object
});
I was sending data form PHP and PHP treats Number and string as seperate datatype.
So I converted those Number data to string and now It works as desired and also I leart that whenever I use <form name='newForm> angularJS creates a new scope named newForm so that I can you many properties of that scope like $dirty, $pristinem $submitted and many more. so Now I dont have to write this logic by myself
I am trying to pass some data to a function but I'm facing an issue with the code below. I can't seem to make it work when i try to use $(this).data("id") if I just use ABC as a value it works.
$(".printLabel").click({
recordId: $(this).data("id")
}, printLabel);
function printLabel(event){
var data = event.data;
console.log(data.recordId);
}
Within the object you provide this is a reference to the window, not the clicked element, hence the data attribute you're looking for is undefined.
Assuming that the data attribute is on the .printLabel element itself, you can retrieve it within the event handler directly without sending any event arguments. Try this:
$(".printLabel").click(function() {
var recordId = $(this).data("id")
console.log(recordId);
});
Why is it a problem calling the function in a more understandable manner? Also if you insist on passing an object, you need to use the object passed - var data = event.data; would not work either. Here is my suggestion using an object too:
$(".printLabel").on("click",function() {
printLabel( {recordId: $(this).data("id")});
});
function printLabel(passedObject){
console.log(passedObject.recordId);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="printLabel" data-id="ID1">This is id1</div>
First things first: I'm not sure whether the information that I'm going to provide will be enough, I will happily add additional information if needed.
I'm serializing a complex structure into the JSON-Format, Field[i][0] is the "this"-reference to an object.
Firebug's Output on JSON.Stringify(myObj)
This is all fine and working as long as I keep it all JS. But now I have the requirement to serialize and send it to my backend to get the reference + computed information back.
Now how do I map back to the reference I had before? How do I bind this ref back to an Object?
This $$hash thing looks internal and proprietarish so I havent even bothered trying something like Object[$$hash] = ref or whatever.
This general idea probably seems pretty whack, but the result is returned asynchrously and I need an identifier to bind the new information back to the original object. Obviously I could just make up my own identifier for that, but I was wondering whether there's an option to solve it this way.
EDIT
The objects are created like this (likewise)
var arrayOfObj = []
arrayOfObj.push(new Object.With.SomeSettersAndGetters());
The Object has a method like
function GetRef(){
return this;
}
Which I'm using to keep a ID/Ref through my code.
Thank you!
Update
If you want to update a series of instances and make many Ajax requests, then you need to look at Ajax long polling and queueing techniques. You won't be able to preserve the reference, but regardless of what Ajax technique you use, make use of the below trick to preserve the reference.
Add long polling on top and you're good to go.
The idea is this:
Assume the server will respond in JSON format. If you need to refer to the original references, here's my two cents:
Update the exact references when the server replies. Say you have 10 instances of Something stored in an array. On a successful response, you use the methods in the Something class to update the specific instances in whatever way you want.
/**
* The array with something instances.
* #type {Array.<Something>}
*/
var instances = [];
/**
* The Ajax success function.
* #param {Event} event The event object.
*/
function ajaxSuccess(event) {
var response = event.target.getResponseText();
var actualResponse = JSON.parse(response);
for (var i = 0, len = actualResponse.length; i++) {
instances[i].setWhatever(actualResponse[i].whatever);
};
};
The above is a more procedural approach. If you want full blown OOP in JS, then you think in modular design patterns. Say you have a module that loads data into some place. Basically, everything related to that module is an instance property.
var myModule = function() {
this.whatever = 1;
};
myModule.prototype.loadMore = function() {
var request = new XMLHttpRequest(),
that = this; // store a reference to this.
request.send(); // etc
request.onreadystatechange = that.onSucess;
};
myModule.prototype.onSucess = function(event) {
var response = JSON.parse(event.target.getResponseText());
this.whatever = response.whatever;
};
var moduleInstance = new myModule();
myModule.loadMore();
// Now the scope is always preserved. The callback function will be executed in the right scope.
Let's assume on the backend side of things, you have a model class that mimics your client side JavaScript model. Say you want to update a reference inside a model that displays text. I use Scala on the backend, but look at the fields/properties and ignore the syntax.
case class Article (
title: String,// these are my DB fields for an Article.
punchline: String,
content: String,
author: String
);
// now assume the client is making a request and the server returns the JSON
// for an article. So the reply would be something like:
{"title": "Sample title", "punchline": "whatever", "content": "bla bla bla boring", "author": "Charlie Sheen"};
// when you do
var response = JSON.parse(event.target.getResponseText());
// response will become a JavaScript object with the exact same properties.
// again, my backend choice is irrelevant.
// Now assume I am inside the success function, which gets called in the same scope
// as the original object, so it refers TO THE SAME THING.
// the trick is to maintain the reference with var that = this.
// otherwise the onSuccess function will be called in global scope.
// now because it's pointing to the same object.
// I can update whatever I want.
this.title = response.title;
this.punchline = response.punchline;
this.content = response.content;
this.author = response.author;
// or I can put it all in a single variable.
this.data = response;
What you need to remember is that scope needs to be preserved. That's the trick.
When I do var that = this; I copy a reference to the model instance. The reference is remembered through higher-order, not current scope.
Then I tell the XMLHttpRequest object to call that.ajaxSuccess when it is complete. Because I used that, the ajaxSuccess function will be called in the scope of the current object. So inside the ajaxSuccess function, this will point to the original this, the same instance.
JavaScript remembers it for me it when I write var that = this;
Scenario:
The MVC web page gets JSON object with lots of data. Upon click of button (there are quiet a number of buttons) I would like to reuse this JSON object and select required JSON Properties (without making a request to server).
It's not HTML5 so can't use browser local storage. At the moment I'm storing the JSON object on GLOBAL variable and reusing it.
Are there any elegant options available to store and re-use returned JSON object on client side?
Just cache the data. There is no need to store the JSON in a global variable, I'm sure you'll find a place in your MVC application to scope a local variable. You will have implemented a getter function for the data with a callback. With caching, it'll look like this:
var getData = (function(){
var cache;
var loading = false;
var callbacks = [];
return function(callback) {
if (typeof cache != "undefined")
callback(cache);
else {
callbacks.push(callback);
if (!loading) {
loading = true;
doSingleHeavyAjaxCall(options, function success(data) {
cache = data;
for (var cb; cb = callbacks.shift();)
cb(cache);
});
}
}
};
})();
Then use getData(function callback(data){...}) as often as you want, and it will only trigger one ajax request.
Another option to Jakubs answer is creating a global variable that you can update and retrieve as you like on the page.
Global variables get attached to the window object, so just write this in your <head> section.
<script type="text/javascript">
window.jsonData = {};
</script>
Then wherever you're retrieving your data just update that object.
<script type="text/javascript">
$.ajax(..., function(data) {
window.jsonData = data;
});
</script>
Then you can use it wherever you like in your code on that page.
<script type="text/javascript">
console.dir(jsonData);
</script>
You can store the object in data- attribute of some element - preferably container for the part of your page that represents your data (table, grid):
var json = {};
$('#mygrid').data('mydata', json);
You can retrieve it later
var json = $('#mygrid').data('mydata')
jQuery data() method documentation: http://api.jquery.com/data/