How to convert JSON array to JavaScript Array? - json

I am using KnockoutJS for data binding.
Following code is controller's action method
public JsonResult GetPeople()
{
var people = new List<Person>
{
new Person {Name = "aaaa", Address = "aaaaaaaaa"},
new Person {Name = "bbbb", Address = "bbbbbbbbb"},
new Person {Name = "cccc", Address = "ccccccccc"}
};
return Json(people, JsonRequestBehavior.AllowGet);
}
And bellow is the snippet of client side code
<ul data-bind="foreach: people">
<li>NAME:<span data-bind="text: Name"></span></li>
<li>ADDRESS:<span data-bind="text: Address"></span></li>
</ul>
<script>
function getPeopleFromServer() {
var people= [];
$.ajax({
url: "GetPeople",
cache: false,
type: "GET",
success: function (result) {
console.log("result= " + result);
people = $.parseJSON(result);
console.log("people= " + people);
}
});
return people;
}
function ViewModel() {
var self = this;
// data
self.people = ko.observableArray(getPeopleFromServer());
}
ko.applyBindings(new ViewModel());
</script>
The problem is that people variable in the getPeopleFromServer method is always null while result has proper value from the server.
Am I missing something?

Your $.ajax function is taking longer to complete than it's containing function, and so the containing function never popuplates people by the end of execution
One thing you can do is to add the following to your $.ajax:
$.ajax({
async: false,
url: "GetPeople",
.....
});
async: false will make the containing function 'wait' until ajax is finished. Your people var should be populated by the end of function execution. While this is a quick win, I agree with Tom that you should re-think how your ViewModel is handled.

#tom's comment is correct.
'success' is an inline async function. Basically, 'return people' happens before the 'success' function is called, because the ajax call is non-blocking. You need to redesign your ViewModel to work asynchronously (or turn off async), hopefully others will chime in with code fixes
Here's the fully commented fiddle he prophesied.
http://jsfiddle.net/bczengel/8Wqum/

people should be referred to either in the same view model. Or as self.people. I suggest you put the call to ajax inside the view model and then it will be clear.
So getPeopleFromServer() should be inside the viewmodel.
Out of interest you can also add
timeout: 600000 so that the call doesnt timeout.

Try to use ko.mapping plugin.
function ViewModelWrapper(jsonResult)
{
var self = this;
self.model = ko.mapping.fromJS(jsonResult);
}
http://knockoutjs.com/documentation/plugins-mapping.html

Related

Weird JSON, how to access needed value

This is the JSON response:
I need to access data[1], which is 0.2. How do I get it?
Here's the actual code:
function getTheValue(){
var result = $.ajax({ url: "https://www.blahblah.com/json" });
return result;
}
console.log(getTheValue());
Here's another way I tried, no luck:
var val = getTheValue();
console.log(val.responseJSON.dataset.data[0][1]);
Your getTheValue function is not returning the JSON response from the AJAX call. It is returning a promise object, since it is actually a doing an asynchronous call. I suggest you read documentation for jQuery.ajax() for more information.
Anyway, you can fix your problem by doing this:
var val;
getTheValue().done(function(response) {
val = response.dataset.data[0][1];
});
The response you're seeing is the ajax object, not the return from the function. $.ajax is asynchronous, so the value isn't available until immediately.
Adapted from the jQuery docs:
$.ajax({
url: your_url,
})
.done(function( result ) {
console.log( result );
});
will give you result. Your subsequent code will need to be triggered inside that done() function.
This finally helped me:
var tBill = getTheBill();
function getTheBill(){
var result;
$.ajax
({
url: "https://www.blahblah.com/json",
context: document.body,
async: false
}).done(function(val) {
result = val;
});
return result.dataset.data[0][1];
}
Guys, thanks for your help! jimm101, you rock.
That object isn't json in its common sense but an Javascript object, if you want the ajax result you have to use a callback:
$.ajax({
url: "https://www.blahblah.com/json" ,
dataType: "json",
})
.done(function(data) {
console.log(data);
});

AngularJS problems with $resource and web servers

I have been testing this code for 2 months, it is the first exercise in my tutorial to learn AngularJS.
The challenge is to count all .json files in a folder and increment it with 1 so that when I save another json file it will always have a higher ID then the previous one. I am having lots of trouble with web servers, first of all NodeJS does not seem to allow JSON posts in its standard configuration. So I have found a modified web-server.js from stockoverflow from a different question:
$resource.save is not functioning
https://github.com/glepretre/angular-seed/commit/9108d8e4bf6f70a5145b836ebeae0db3f29593d7#diff-d169b27b604606d4223bd5d85cad7da1 I have also tried the web-server.js that came with the tutorial:
http://pastebin.com/Ckfh4jvD that seemed to work better. WAMP also did not work I could not get Apache to allow JSON posts.
Problem is the web-server posts the json or sees the json as an object not as an array, even though I have used "isArray: true" and I use .query() instead of .get(). And I have tried many other things like transformResponse: []. I need the array to get .length to work! Also sometimes it GETS an array and POSTS an object which it later reads as object again it is getting really weird.
The code works sometimes as posted or sometimes I need to change :id to :id.json, usually this means the server is retrieving it as an object again which is not what I wan but this differs between the 2 nodeJS servers.
.factory('eventData', ['$resource', '$q', function ($resource, $q) {
var resource = $resource('/app/data/event/:id', {id: '#id'}, {"getAll": {method: "GET", isArray: true}});
var number = resource.query();
console.log(number);
return {
getEvent: function () {
var deferred = $q.defer();
resource.get({id: 1},
function (event) {
deferred.resolve(event);
},
function (response) {
deferred.reject(response);
});
return deferred.promise;
},
save: function (event) {
var deferred = $q.defer();
event.id = number.length;
resource.save(event,
function (response) {
deferred.resolve(response);
},
function (response) {
deferred.reject(response);
}
);
return deferred.promise;
}
};
}]);
EDIT: This seems to work better however I need to figure out how to put an .then() into this service?
.factory('eventData', ['$resource', '$q', function ($resource, $q) {
var resource = $resource('/app/data/event/:id.json',
{id: '#id'}, {method: "getTask", q: '*' },
{'query': { method: 'get'}});
var number = resource.query();

viewbag data is empty in $.ajax

Iam using asp.net mvc4 and facing some problem in accessing viewbag.price.
This is what i am doing:-
[HttpPost]
public ActionResult FillModel(int id)
{
var vehModel = db.Vehicle_Model.Where(vehMod => vehMod.MakeID == id).ToList().Select(vehMod => new SelectListItem() { Text = vehMod.Model, Value = vehMod.pkfModelID.ToString() });
ViewBag.Price = 100;
return Json(vehModel, JsonRequestBehavior.AllowGet);
}
i am calling above using below:-
$.ajax({
url: '#Url.Action("FillModel","Waranty")',
type: 'post',
data: { id: id },
dataType: 'json',
success: function (data) {
$('#ddModel').empty();
$.each(data, function (index, val) {
var optionTag = $('<option></option>');
$(optionTag).val(val.Value).text(val.Text);
$('#ddModel').append(optionTag);
});
var a = '#ViewBag.Price';
},
error: function () {
alert('Error');
}
});
But i am not able to access ViewBag.Price.
Anyone know the reason??
thanks
The reason you aren't able to access items from the ViewBag inside your ajax success function is because the view that contains your script has already been rendered by the Razor view engine, effectively setting the variable a to whatever the value of #ViewBag.Price was at the time the page was rendered.
Looking at the process flow might be helpful:
(1) The request comes in for the view that has your script fragment in it.
(2) The controller method that returns your view is called.
(3) The Razor view engine goes through the view and replaces any references to #ViewBag.Price in your view with the actual value of ViewBag.Price. Assuming ViewBag.Price doesn't have a value yet, the success function in your script is now
success: function (data) {
$('#ddModel').empty();
$.each(data, function (index, val) {
var optionTag = $('<option></option>');
$(optionTag).val(val.Value).text(val.Text);
$('#ddModel').append(optionTag);
});
var a = '';
}
(4) The rendered html gets sent to the client
(5) Your ajax request gets triggered
(6) On success, a gets set to the empty string.
As you had mentioned in the comments of your question, the solution to this problem is to include a in the Json object returned by your action method, and access it using data.a in your script. The return line would look like
return Json(new {
model = vehModel,
a = Price
});
Keep in mind that if you do this, you'll have to access model data in your ajax success function with data.model.Field. Also, you shouldn't need to specify the JsonRequestBehavior.AllowGet option, since your method only responds to posts and your ajax request is a post.

How to synchronize returning function values in jQuery?

I have written this function in jQuery:
function checkAvailability(value) {
var result = true;
$.getJSON("registration/availability", { username: value }, function(availability) {
if (!availability)
result = false;
alert("in getJSON: " + result);
});
alert(result);
return result;
}
I have got alert from 'getJSON' after this second. Why has it happened this way?
I have Spring MVC project and Controller method which checks username availability. Controller method works properly. But I receive final result too late. How can I synchronize it to return properly value in my function?
EDIT
I am using this function in jQuery validate. I have extracted checkAvailability() function during my test.
$.validator.addMethod("checkAvailability", function(value, element, param) {
var das = checkAvailability(value);
return das;
}, jQuery.format("Someone already has that username. Please try another one."));
And this is my form validate:
$(".form").validate({
rules: {
username: {
checkAvailability: true
},
....
},
messages: {
}
});
EDIT 2
This is my Controller method. It returns boolean value. If username was taken it would return false value.
#RequestMapping(value="/registration/availability", method = RequestMethod.POST)
public #ResponseBody boolean getAvailability(#RequestParam String username) {
List<User> users = getAllUsers();
for (User user : users) {
if (user.getUsername().equals(username)) {
return false;
}
}
return true;
}
Why does this behave this way?
$.getJSON is shorthand for making an AJAX request. The 'A' in ajax stands for asynchronous. Meaning, the javascript engine fires the getJSON call and then immediately executes the next lines, which is alert(result); return result;
The actual value as returned by the web service will be received by your code at a later point in time. The success function that you passed into getJSON will be called once the js engine receives the response from the server. As you can see, it is too late by that point.
Further reading: https://developer.mozilla.org/en/AJAX
What can I do to make this work?
That depends on your situation. Who is calling checkAvailabilty? If you post some code on how this function is being used, I can give examples with my suggestions.
Off the top of my head, you could either make use of jquery deferreds, nice article on the same. Or you could pass in a callback function that is executed from inside your success function.
EDIT:
http://docs.jquery.com/Plugins/Validation/Methods/remote#options
The serverside resource is called via $.ajax (XMLHttpRequest) and gets
a key/value pair, corresponding to the name of the validated element
and its value as a GET parameter. The response is evaluated as JSON
and must be true for valid elements, and can be any false, undefined
or null for invalid elements,
To get a real world idea, check the demo http://jquery.bassistance.de/validate/demo/captcha/
Open Firebug or the developer tools of your choice. Go to the tab that lets you see AJAX requests. Enter the captcha, submit. Check ajax request as listed in the developer tool. Notice the query string parameters. Notice the response. Its a simple 'true' or 'false'.
Not sure if this helps or not but you can use
var result;
$.ajax( {
url : "registration/availability",
data : data,
async : false //syhcrononous ajax request ;)
}).done(function(data) {
result = data;
});
for more info you can refer JQuery AJAX doc

Help using Mootools and JSONP

I am having a really hard time trying to get this to work. All I require is to console log the object that is returned. I see nothing at all in the log although the script tag is getting injected into the head.
JSON:
jsonFeed({
"results":{
"loggedin": "No",
"username": "",
"company": ""
}
});
JS:
function jsonFeed() {
}
window.addEvent('domready', function() {
new Request.JSONP({
url: <correcturl>,
onComplete: function(data){
console.log(data); // Nothing returned
}
}).send();
});
Any help is greatly appreciated.
UPDATE
I have removed the jsonFeed function at the top and changed the existing code to:
new Request.JSONP({
log: true,
url: loginstatus,
callbackKey: 'jsonFeed',
onComplete: function(data){
console.log(data); // Nothing returned
}
}).send();
In the log I get:
JSONP retrieving script with url:http://thedomain/LoggedStatus.aspx?jsonFeed=Request.JSONP.request_map.request_0
jsonFeed is not defined
In the this gets injected:
<script type="text/javascript" async="true" src="http://thedomain/LoggedStatus.aspx?jsonFeed=Request.JSONP.request_map.request_0">
-- if I expand this I see the JSON --
</script>
so a) I'm getting the jsonFeed not defined error and b) the onSuccess isn't firing :(
I really do appreciate all your help guys. And I am sorry if I am missing the point :(
UPDATE
added:
this.jsonFeed = function(data) {
console.log(data);
};
.. and it works. Thank you #Dimitar
I still don't quite understand it but now it works it helps when working it out.
it does not work because your callback function name ignores the one that Request.JSONP sends and returns jsonFeed instead.
http://mootools.net/docs/more/Request/Request.JSONP
callbackKey (string: defaults to callback) the key in the url that the server uses to wrap the JSON results. So, for example, if you used callbackKey: 'callback' then the server is expecting something like http://..../?q=search+term&callback=myFunction; This must be defined correctly.
here's an example class i wrote that gets stuff off of flickr - who use a custom callback key - it's fine. http://fragged.org/mootools-flickr-api-class-via-request-jsonp_1042.html (p.s. jsfiddle may be slow atm, friday 13th thing!)
the other thing is, if the remote end CONTINUES not to work with you and refuses to send data in the correctly wrapped format, eg:
Request.JSONP.request_map.request_0({data})
then you need to actually make sure that
this.jsonFeed = function(data) {
console.log(data);
};
where this is the global object (eg, window) - you cannot scope this, so careful where the function is defined.
if doing the latter, jsonFeed will then take the role of a callback oncomplete function.
another way is to do this, which will map the native callback function defined by the class and export it to the one your remote host likes:
onRequest: function() {
var lastCallback;
Object.each(Request.JSONP.request_map, function(el) {
lastCallback = el;
});
window.jsonFlickrApi = lastCallback;
},
onComplete: function(data) {
...
}
jsonFeed(
return //or anything else that will make this piece of data recognizable on your page
{
"results":{
"loggedin": "No",
"username": "",
"company": ""
}
});
new Request.JSONP({
url: <correcturl>,
callbackKey: 'jsonFeed'
onComplete: function(data){
console.log(data); // Nothing returned
}
}).send();