У меня есть решение этой проблемы, которое работает со мной до сих пор (проверено только на 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"}]
Адено уже указал на это, ваш синтаксис 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)},
пропускает кавычки вокруг строки функции.
$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
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);
JSON не может содержать такие функции.
Тем не менее, вы можете использовать Javascript для внедрения функции в DOM, так что вам нужно пропустить str_replace
часть и просто создать <script type="text/javascript"></script>
элемент в DOM и вставьте data.function
собственность в там.