Правильный возврат объекта JSON со встроенной функцией JS

Обновленный пост

У меня есть решение этой проблемы, которое работает со мной до сих пор (проверено только на Firefox).
Моей главной целью было динамическое обновление Flot граф с Ajax. Мне также нужно динамически обновлять стили осей, и вы можете сделать это с помощью tickFormatter вариант. Чтобы избежать проблем, которые у меня были ранее, я просто вставляю возвращаемая строка в массиве PHP и JSON кодируют этот массив. После возвращения в функцию Ajax я создаю новую функцию, используя JavaScript Функция () конструктор (Ссылка на сайт). Я надеюсь, что это помогает кому-то.

Ajax

$.ajax({
url: 'someControllerWhichCreatesJSONdata',
data: 'some Value',
type: 'post',
cache: false,
datatype: 'json'
})
.success(function(data) {
var datas = data[0];    // fetch data array
var options = data[1];  // fetch options array
var xReturn = options.xaxes[0].tickFormatter; // fetch return string
var yReturn = options.yaxes[0].tickFormatter;
var xFunc = new Function("val", "axis", xReturn); // create function
var yFunc = new Function("val", "axis", yReturn);
options.xaxes[0].tickFormatter = xFunc; // update tickFormatter with function
options.yaxes[0].tickFormatter = yFunc;

$.plot($("#yw0"), datas, options);
})
.error(function(data) {
$("#error").html(data.responseText); // show error in separate div
});

PHP массив

$options = array(
'legend' => array(
'position' => 'nw',
'show' => true,
'margin' => 10,
'backgroundOpacity' => 0.5
),
'grid' => array(
'clickable' => true,
'hoverable' => true
),
'pan' => array('interactive' => true),
'zoom' => array('interactive' => true),
'axisLabels' => array('show' => true),
'xaxes' => array(
array(
'axisLabel' => 'someUnit',
'tickFormatter' => 'return "foo bar"' // enter whatever return value you need
)
),
'yaxes' => array(
array(
'axisLabel' => 'someUnit',
'tickFormatter' => 'return "foo bar"'
)
)
);

Я пропускаю массив данных, так как он выглядит аналогично. Оба массива объединяются и кодируются в формате JSON.

public function actionSomeControllerWhichCreatesJSONdata() {
$returnArray = array($data, $options);
echo json_encode($returnArray);
return true;
}

Полученный массив выглядит как тот, который я выложил внизу этого поста.

Оригинальный пост

Я пытаюсь часами, но я не могу заставить это работать.

У меня есть запрос Ajax, который получает объект JSON в качестве возвращаемого значения в случае успеха. Это прекрасно работает, пока я не использую функцию JS в моем массиве JSON. Так что мой массив JSON выглядит следующим образом (после json_encode):

[{
"data": [{
{1,2},
{3,4},
}],
"function": "function(){return \"foo bar\";}"}]

Чтобы избавиться от «находится в строке функции. я использую str_replace и заменить строку в кавычках на строку без кавычек. Тогда это выглядит так:

[{
"data": [{
{1,2},
{3,4},
}],
"function": function(){return "foo bar";}
}]

Простой json_encode работает нормально, и моя функция Ajax читает его как объект JSON. После замены строки выясняется, что возвращаемое значение больше не является объектом JSON, а представляет собой текстовую строку. Я попытался снова разобрать строку с jquery.parseJSON () но это приводит к синтаксической ошибке:

SyntaxError: JSON.parse: неожиданное ключевое слово в строке 1 столбца 396 данных JSON

Функция Ajax:

$.ajax({
url: 'someControllerWhichCreatesJSONdata',
data: 'some Value',
type: 'post',
cache: false,
datatype: 'json' // or text when trying to parse
})
.success(function(data) {
console.log(data);
var dat = jQuery.parseJSON(data);  // trying to parse (only when dataType: "text")
var datas = dat[0];                // or data[0] when datType = json
var options = dat[1];              // ---
$.plot($("#yw0"), datas, options); // trying to update a FLOT window
})
.error(function(data) {
console.log("error");
$("#error").html(data.responseText); // show error in separate div
});

Поэтому при использовании этой функции и установке типа возвращаемого значения «JSON», это выдает ошибку. Если тип возврата «текст» и я пытаюсь разобрать строку, я получаю ошибку выше. Есть ли решение этой проблемы или я делаю что-то совершенно не так?

Спасибо за вашу помощь!

ОБНОВИТЬ
Извините, конечно, мои данные JSON недействительны! Как я уже сказал, мой JSON-объект создается json_encode который, я думаю, должен получить правильный синтаксис. Простой массив после son_encode выглядит так:

[[{
"data":[[0.0042612,0.0042612]],
"label":"WISE.W3: Cutri et. al 2012",
"lines":{"show":false},
"points":{"show":true,"radius":3}}],
{
"legend": {
"position":"nw",
"show":true,
"margin":10,
"backgroundOpacity":0.5},
"grid": {
"clickable":true,
"hoverable":true},
"pan":{"interactive":true},
"zoom":{"interactive":true},
"axisLabels":{"show":true},
"axisLabel": {
"unit":"Jy",
"id":null,
"name":null},
"tickFormatter":"$tickFormatter$",
"position":"right"}]

и после str_replace я получил

[[{
"data":[[0.0042612,0.0042612]],
"label":"WISE.W3: Cutri et. al 2012",
"lines":{"show":false},
"points":{"show":true,"radius":3}}],
{
"legend": {
"position":"nw",
"show":true,
"margin":10,
"backgroundOpacity":0.5},
"grid":{"clickable":true,"hoverable":true},
"pan":{"interactive":true},
"zoom":{"interactive":true},
"axisLabels":{"show":true},
"axisLabel":{"unit":"Jy","id":null,"name":null},
"tickFormatter":function(val, axis){return val.toExponential(2)},
"position":"right"}]

2

Решение

Адено уже указал на это, ваш синтаксис JSON недействителен.
Пожалуйста, попробуйте подтвердить ваш JSON с линтером, как http://jsonformatter.curiousconcept.com/

Это немного лучше:

[{"data":[["1","2"],["3","4"]],"function":"function(){return \"foo bar\";}"}]

И еще одна вещь: вы не должны десериализовать JSON вручную. Все более новые версии jQuery будут автоматически десериализовать JSON на основе заголовка типа содержимого ответа.

Вы уже установили dataType в json для запроса ajax.
Ответ JSON и будет десериализован.
Таким образом, вы можете напрямую использовать

.success: function(response) {
console.log(response.data);
console.log(response.function);
}

Ответьте на вопросы / вопрос из комментариев:

Теперь вы снова создали неверный JSON, потому что "tickFormatter" : function(val, axis){return val.toExponential(2)}, пропускает кавычки вокруг строки функции.

  • Прежде чем вставлять строку с помощью str_replace (), вам нужно позаботиться о экранировании и цитировании.
    Вам может понадобиться небольшая вспомогательная функция, которая правильно экранирует строку — чтобы быть действительным JSON.
  • вам нужно правильно использовать str_replace (): не заменять внешние кавычки, а только внутренние $tickFormatter$,

Подождите .. я приведу пример:

    // we already have an array, which is JSON encoded
// now you want to insert additional JSON content.
// therefore we use a token replace approach.

// valid JSON - with $token$

$json = '[{"data":[["1","2"],["3","4"]],"tickFormatter":"$tickFormatter$"}]';

// the (future) javascript function is a string.
// it's not properly escaped or quoted to be JSON
// this allows for copy and pasting JS into PHP
$unescaped_functionString = 'function(){return "foo bar";}';

// in order escapre properly, we need a json escaping helper

/**
* @param $value
* @return mixed
*/
function escapeJsonString($value) { # list from www.json.org: (\b backspace, \f formfeed)
$escapers = array("\\", "/", "\"", "\n", "\r", "\t", "\x08", "\x0c");
$replacements = array("\\\\", "\\/", "\\\"", "\\n", "\\r", "\\t", "\\f", "\\b");
$result = str_replace($escapers, $replacements, $value);
return $result;
}

// then we escape the function string

$functionString = escapeJsonString($unescaped_functionString);

// now its ready to be inserted into the existing JSON,
// where token $tickFormatter$ is defined
// the token must be in single quotes. you replace just the $token$ and not "$token$".

$json = str_replace('$tickFormatter$', $functionString, $json);

echo $json;

// The result is valid JSON again:
// [{"data":[["1","2"],["3","4"]],"tickFormatter":"function(){return \"foo bar\";}"}]

Следующий шаг:
Сделан запрос ajax, данные json переданы клиенту, и вы хотите выполнить переданную вами функцию.

Итак, новый вопрос: «Как вызвать / выполнить функцию JavaScript из строки — без использования eval?»

В общем, туннелирование — плохая практика, смотрите: Допустимо ли определять функции в результатах JSON?

Во всяком случае, есть разные способы сделать это:

Реферирование: http://everythingfrontend.com/posts/studying-javascript-eval.html

  • eval () — зло, но работает.
  • SetTimeout ()

    setTimeout(" function ", 0);
    
  • новая функция ()

    var codeToExecute = "My.Namespace.functionName()";
    var tmpFunc = new Function(codeToExecute);
    tmpFunc();
    
  • document.write

    document.write('<script> JS </script>')
    
  • URI данных

    var s = document.createElement('script');
    s.src = 'data:text/javascript,' + encodeURIComponent('alert("lorem ipsum")')
    document.body.appendChild(s);
    
3

Другие решения

JSON не может содержать такие функции.
Тем не менее, вы можете использовать Javascript для внедрения функции в DOM, так что вам нужно пропустить str_replace часть и просто создать <script type="text/javascript"></script> элемент в DOM и вставьте data.function собственность в там.

0