JSON-Response with "full objects" not possible?

Hey Everybody,

I want to make a $.ajax-Call via jQuery to a Controller-URL. That works and I run through a Method and my Response is a DB-Result. If I print it out in a PHP-Block I can access e.g. sub-objects like:

echo $appointment->task->name; //e.g. print’s out “wash car”… that’s no problem.

But I want to have this response in jQuery ajax onComplete, that’s also no Problem, but in my Response there is not a filled “task-object” (employee and customer are not filled as well, but let’s keep it to the task-example) - so I only can access the task-id but not the name!!!

My Response-Text in jQuery is:


[{"id":"2","date":"2011-02-23 14:00:00","confirmed_at":"2011-02-23 11:00:00","customer_id":"3","task_id":"1","employee_id":"2"}]

This is caused by using YII-Methods "CJSON::encode($var)" (I also tried CJavaScript::jsonEncode($var))

So but no one of this two possibilites does give me a fullfilled JSON-XML-Response with a filled task-object (I need the name) and so on.

Is that not possible with YII? I excpect it nowadays as a basic functionality :-\

Thank you very much for every kind of help!

CJSON::encode works normally very well.

Did you try to compare your JSON result with var_dump?

Are you trying to encode an active record?

I think CJSON::encode does not support object recursion…




case 'object':

            if ($var instanceof Traversable)

            {

                $vars = array();

                foreach ($var as $k=>$v)

                    $vars[$k] = $v;

            }

            else

                $vars = get_object_vars($var);

            return '{' .

                   join(',', array_map(array('CJSON', 'nameValue'),

                                       array_keys($vars),

                                       array_values($vars)))

                   . '}';



I guess, you will have to first encode your task object and give the return value (as string) to your $appointment->task = CJSON::encode($appointment->task); and then encode your $appointment object… should work.

If you plan to use models, see http://www.yiiframework.com/extension/ejsonbehavior/

Cheers

Hey Antonio,

thanks for your hint. I tried several things, so if you like, let’s talk about it, because I detected some awful behaviours, if I did not some mistakes. I think my approach here is not unusual, so I still wonder, why is it such a circumstance :-\

I present you now my analysis and checkings:

controller-code:




class CalendarController extends controller {

   public function actionShowWeekDates(){

        $criteria = new CDbCriteria();

        $criteria->condition = 'employee_id=2';

        $appointments = Appointment::model()->findAll($criteria);


        for ($i = 0; $i != sizeof($appointments); $i++){

            $appointments[$i] = $appointments[$i]->toJSON(); //I use the EJsonBehavior.php!

        }


        $appointments = CJavaScript::jsonEncode($appointments);

        echo $appointments;

   }

}



My JS-Code inside the Page (i have a very javascript-based calendar, so i need to use javascript without any JS->PHP interaction)

JS-Function-Code Ajax-Code (I use jQuery 1.5!):




$.ajax({

                url: 'calendar/showWeekDates',

                dataType: 'json',

                data: {

                    /*....*/

                },

                complete: function(jqXHR, textStatus){

                    var response = jqXHR.responseText;


                    /*

                         first try to encode with JSON from json.org

                         http://json.org/js

                         json.js: https://github.com/douglascrockford/JSON-js/blob/master/json.js

                    */

                    var JSONObject = JSON.parse(response);


                    /*

                         second try to encode with jQuery parseJSON

                         http://api.jquery.com/jQuery.parseJSON/

                    */

                    var JSONjQueryObject = jQuery.parseJSON(response);

                }

});



So, now comes the big battle. Now I expect a full qualified JavaScript Object to access the datas inside.

My Response:




[

    "{'attributes':{'id':'1','date':'2011-02-23 14:00:00','customer_id':'1','task_id':'1','employee_id':'1'},'relations':{'customer':{'id':'1','first_name':'Sandra','last_name':'Bullock','email':'sandra@bullock.com'},'task':{'id':'1','name':'Massage'},'employee':{'id':'1','name':'Marco','email':'email@provider.com'}}}"

]



But neither the JSON.parse() nor the jQuery.parseJSON() results in an JavaScript-Object to access the data!!!

I’m a bit dissappointed from Yii, that seems to be a basic approach from behaviour with ajax, json and requesting the controller’s data. What I’m doing wrong, what can I do better?

My temporarily Solution to have a JavaScript-Object to access data is now:




$.ajax({

                url: 'calendar/showWeekDates',

                dataType: 'json',

                data: {

                    /*....*/

                },

                complete: function(jqXHR, textStatus){

                    var response = jqXHR.responseText;


                    var JSONObject = jQuery.parseJSON(response);


                    var evaledJson = eval('(' + JSONObject[0] + ')');

                }

});



And now with the additional parsing via “eval(’(’ + JSONObject[0] + ‘)’)” I can access the full object for example the task-name: “alert(evaledJson.relations.task.name);”!

In case of this Problem, I tried to research for this problem. But it was difficult, because it seems to be only a Yii-"Problem" or better so say behaviour.

I googled a lot and I think the response datas are not that correct that json-parser and jquery json-parser needed to be, so If i pass the result via http://www.jsonlint.com/ the result seems to be correct :open_mouth: !

Why I’m thinking the parsed result JSON-Structure (caused by Controllers “toJSON()”-Method in the for-loop) is that the very most information that I google (e.g. this google result) the JSON-Result-Structure seems to be a little different! For Example, If I take this kind of JSON-syntax would expect the response-result above to be like:




{

    "attributes" : [

        {

            "id": "1",

            "date": "2011-02-23 14:00:00",

            "customer_id": "1",

            "task_id": "1",

            "employee_id": "1"

        }

    ],

    "relations" : [

        {

            "customer": [

                {

                    "id": "1",

                    "first_name": "Sandra",

                    "last_name": "Bullock",

                    "email": "sandra@bullock.com"

                }

            ],

            "task": [

                {

                    "id": "1",

                    "name": "Massage"

                }

            ],

            "employee": [

                {

                    "id": "1",

                    "name": "Marco",

                    "email": "email@provider.com"

                }

            ]

        }

    ]

}



again my original Response was:




[

    "{'attributes':{'id':'1','date':'2011-02-23 14:00:00','customer_id':'1','task_id':'1','employee_id':'1'},'relations':{'customer':{'id':'1','first_name':'Sandra','last_name':'Bullock','email':'sandra@bullock.com'},'task':{'id':'1','name':'Massage'},'employee':{'id':'1','name':'Marco','email':'email@provider.com'}}}"

]



So, with this knowledge I pasted the "new" SELF MADE Json-Syntax in my Ajax-Response (not the original response - I override and "fake" it):




$.ajax({

                url: 'calendar/showWeekDates',

                dataType: 'json',

                data: {

                    /*....*/

                },

                complete: function(jqXHR, textStatus){

                var response = "{\"attributes\" : [ {\"id\":\"1\",\"date\":\"2011-02-23 14:00:00\",\"customer_id\":\"1\",\"task_id\":\"1\",\"employee_id\":\"1\"}], \"relations\" : [ {\"customer\": [    {\"id\":\"1\",\"first_name\":\"Sandra\",\"last_name\":\"Bullock\",\"email\":\"sandra@bullock.com\"}], \"task\": [    {\"id\":\"1\",\"name\":\"Massage\"}], \"employee\":[ {\"id\":\"1\",\"name\":\"Marco\",\"email\":\"email@provider.com\"} ] } ] }";

              

                var JSONObject = JSON.parse(response); //this way works

               

                var JSONjQueryObject = jQuery.parseJSON(response); //jQuery way works, too

                }

});



and in THIS (both) CASEs, I have directly the Javascript-Object I needed and can access e.g. via "alert(JSONObject.relations[0].task[0].name);" or (jQuery-way): "alert(JSONjQueryObject.relations[0].task[0].name);"

I hope I’m right and you don’t loose the overview, I can split it again a bit to discuss over it in detail, but I would be very pleased if I can have a reliable solution for this case.

Maybe Yii can be optimized with this handling. Again I’m surprised in the case, that I’m doing no mistakes, that no one else was crashing in this problem/question.

Thank you very much!

Interesting issue and I have to confess went through the same about a month a go.

On my research I found that even correct JSON object format ‘{’ for objects ‘[’ for arrays (avoiding other more complex structures), the parsing from Crockford’s code to the simple eval(’(’…’)’); was making a huge difference. With the first I couldn’t even get a “function(){}” within any object attribute, I finally used the ‘evil’ eval for my solution and created a custom JSONencode function to build them.

So, I guess I ended up with your same conclusion but applying different solution to yours. I don’t see any problem with CJSON::encode, but I would love to see if we can come up with a solution where same result is for eval() (drupal.js) that it is for the Crockford’s and jquery.parseJSON parser.

I believe that to do that, we will have to mimic the exact result used by Crockford’s and jquery’s parseJSON (they just use the Function constructor).

I see on your solution that the only difference was the array bracket wrapper per JSON object. Did you tried with functions?

Would be better to use the success callback for $.ajax,

The response data will be in the first param for the function, jQuery will also try to detect the datatype and auto decode json.


$.ajax({

   success: function(data) {

      //Use data here.

   }

});

Hey alex-w!

Thanks for your advice… you’re right, i tried to change the dataType and with ‘json’ it’s automatically “parsed”, BUT then not automatically accessible!

I must “parse” it anyway with e.g. “var jsResultObj = eval(’(’ + data + ‘)’);”

Or to step over every result set (data is an array of ‘n’ results, in my example two!):


for (var i = 0; i != data.length; i++){

     var jsResultObj = eval('(' + data[i] + ')');

     //access e.g. alert("test = " + jsResultObj.relations.task.name);

}

last question to this, I’m not sure, but I read, that this “eval”-function is unsafe for script-manipulations?!

[quote name="json.org/js"]The eval function is very fast. However, it can compile and execute any JavaScript program, so there can be security issues. The use of eval is indicated when the source is trusted and competent. It is much safer to use a JSON parser.
[/quote]

So If jQuery automatically parses the request to json-string is this issue not interesting for me anymore?

Thank you

Yeah, also they say that we should use carefully the ‘new Function’ constructor and jquery uses that to create an object from a JSON string.

IMHO, test your code, works in all browsers? -I dont include IE6 (if it is not a shopping site of course, wink to samdark ;)), then if it works, use it.

Yes I must say it works like that way with the "eval"-function.

But as I said, I thought it would go a littlebit more comfortable, but it’s ok, it’s just one more function-call!

I don’t check if it works in IE6 - I don’t support <IE8 :slight_smile: That sucks too much!

Thanks a lot guys

Ok. I did a somewhat big ammount of testing and:

I reversed engineered your objects structure from your json

I json_encoded with the php function

i cannot duplicat your finds. I always end up with a correct json result. Somewhere something is going wrong. Please take a look at the object structure i have duplicated, maybe it’s not the same, although it should be. The main difference between what i get and what you get is: after [ and before ] i do not end up with a ". if you look carefoully, that will end up in a js error.

Take that initial response you got, remove the " after [ and before ]. You will end up with a error. BUT: start replacing the simple quotes with double ones. Eventually, you’ll be error free. Again, i have found this by playing, but i still get perfect results with php’s native json_encode.

I hope these informations might make the problem a bit more clear.

PS: the test code is attached here: htt p://pastebin.com/kquqn15U [remove the space.]