Add function to JSON object with php - javascript

Is there any way to add function to JSON object with php?
i have an array in php like this :
$aoData = array(
array('name' => 0, 'value' => "id"),
array('name' => 1, 'value' => "title"),
array('name' => 2, 'value' => "cat"),
array('name' => 3, 'value' => "img"),
array('name' => 4, 'value' => "des"));
and i want add a function like this:
array('name' => 5, 'value' => function(){return "hi"})
and use this function in my jquery.
is there any way for this?
Update
in data table i need to set aoColumnDefs in php.
"aoColumnDefs":
[{
"aTargets": [ img ],
"mData": "thumb_img",
"mRender": function ( data, type, full )
return '<img src="../up/thumb/'+data+'">';
},
{etc}
]
so i need set function as a Json function or another way ...

JSON does not allow function definition for security and compatibility reasons, and as a proof, I don't see any other way than storing a string and use a form of eval (that is using eval or creating a Function with a body). I'd strongly recommend not to do it though.

In order for it to be JSON, and for any JSON library to work with it, no, it is not possible.
JSON is a language and platform independent, portable data serialization scheme and, therefore, has a limited set of things which can be represented within. Functions, given that they are language and platform specific, are not portable.
It is possible to use PHP to "manually" output a JavaScript object which has methods:
<?php
$foo = '{name: 5, value: function () { return "hi";}}'
?>
var js_object = <? echo $foo; ?>;
This is messy and error prone, however, and would not be JSON.

So yeah...
JS Object is not the same as JSON.
Some libs or frameworks will want to add functions to the JS Object.
For example primevue has a menu structure with functions in the Object:
const items = {
label: 'New',
icon: 'pi pi-plus',
command: (event) => {
// event.originalEvent: Browser event
// event.item: Menuitem instance
}
}
;
Nice, but what if you want this data provided from DB via php...?
this works:
const func = 'items.command = function(event){ console.log(event) }'
eval(func)
So we could do something with this.
This means doing something with the JSON when it is loaded into Javascript and turn some strings into functions with eval.
This is of course a security risk.
But somehow we'll need to change the JSON into a JS Object.
Better maybe is to not have info of the end platform in the DB.
The solution I'm using is that I'm pre-defining what commands can be added to the JS Object and use codes to tell the reader what I want added.
switch (add) {
case '[login]':
items.command: () => {
auth.destroyToken()
this.$router.push({ name: 'login' })
}
break;
}
Not as "free", but for security that's a good thing.

You can't add the function as value, but you can add the return value of the function as value of the json object.
So in the example you gave, the value will just be "hi" (if you type return correctly).
I don't see the reason for adding a function into a JSON object, because you can probebly do the same with JQuery and if you can't then use AJAX to get results from the serverside.

Related

JavaScript preserver plain json object while saving to json file

May I know how can I preserve the plain JSON object while I save to .json file and retrieve from the json file in the properly way.
const jsonObj = [
{
min:1,
max:4,
defaultValue:3,
width:"100%",
label:"Column",
onChange:(evt) => adjustGrid("col", evt),
type:"InputNumber"
},
{
min:1,
max:4,
defaultValue:1,
width:"100%",
label:"Row",
onChange:(evt) => adjustGrid("row", evt),
type:"InputNumber"
}
]
The intention of preserving the plain JSON object is because I want to achieve fully dynamic form element controls with the helps of JSON object.
I have attempted to use JSON.stringify but it escape the onChange key-pair which makes I cannot retrieve back the onChange key when I retrieve it from my .JSON file.
the onChange function is not restricted for adjustGrid function, it can be any function that has been defined in the JS file.
The render code will be:
return jsonObj.map((v) => {
return (
<Form.Item label={v.type}>
<InputNumber
min={v.defaultValue}
max={v.max}
defaultValue={v.defaultValue}
{...v}
width={v.width}
/>
</Form.Item>
)
});
You can't get a function from a stringified Object.
You want to keep code in source control, not in data, so it's a bad practice to do that. Also, it's a security hazard to have executable code in data...
I suggest extracting the handlers and using a conditional:
If you have more handlers, you can create a choose handler function, but i just inlined it here...
const InputItem = ()=>{
const rowHandler = (evt) => adjustGrid("row", evt)
const colHandler = (evt) => adjustGrid("col", evt)
return jsonObj.map((v) => {
return (
<Form.Item label={v.type}>
<InputNumber
//...other properties
onChange = {v.label == "Column" ? colHandler : rowHandler}
/>
</Form.Item>
)
});
}
JSON
There is no "JSON Object" to start with, if such a thing can be said to exist: JSON is a notation syntax for serializing data objects. By design it does not serialize object properties that are functions, does not distinguish between null and undefined, and can't encode objects with cyclic property references.
JavaScript
You could use a JavaScript file containing the text in the post - which is JavaScript source code and not JSON anyway. If you don't want to create or make use of global variables in the script, you could use export and import statements for jsonObj from within script files of type "module". The downside for modules is that they are not available using the file:// protocol and must come from a server.

Object behaviour changed after assigned the variable

I have received a query/argument (matchQuery) from the client side through API.
When I console this request.query.matchQuery.on the server side it gives me {"count":{"$gt":1}} this is good for me.
when I assign this argument on the other variable like this
var aggregateQuery = {
$match: request.query.matchQuery
}
and now I console aggregateQuery its returns
{ '$match': '{"count":{"$gt":1}}' }
its behavior gets changed. But I don't want to single quotes on the right
side.
OUTPUT
{ '$match':{"count":{"$gt":1}}}
OR
{ $match:{"count":{"$gt":1}}}
OR
{ $match:{count:{$gt:1}}}
Best way to correct data that receive in serialized JSON is to parse it. JavaScript has JSON global object for facilitate JSON conversion and applied in application.
in your case evidence shows that request that came from client is like this:
"{\"count\":{\"$gt\":1}}"
but in your framework changed to STRING
typeof('{"count":{"$gt":1}}') ==> 'string'
that is not object
for use request.query.matchQuery as java script object your may convert it to JavaScript Object. for more details refer to below example:
var aggregateQuery = {
$match: JSON.parse(request.query.matchQuery)
}
Notice:
If you are not in STRICT MODE by adding
"use strict"
you can execute your code with
eval( code to be execute )
for examlpe
eval(`var e = { '$match':` + '{"count":{"$gt":1}}' + `}`)

using smarty template engine in registered javascript files with prestashop 1.7

I'm writing Prestashop 1.7.2.1 module.
In that module when I want to register a javascript file I connect to the hook actionFrontControllerSetMedia and use registerJavascript like so:
$this->context->controller->registerJavascript('module-tuxinmodcartype-carsearch-js','modules/'.$this->name.'/js/displaytop.js');
this loads the javascript properly but I can't use smarty template engine in those javascript files.
is there a way to do that ? :)
if not... should I just add all my javascript files inline ?
update
so I added this to my hook function:
Media::addJsDef(['tuxinmodcartype'=>array(
'car_companies'=>$this->tuxDb->getCompanyNamesArray()
)]);
and this my js file:
$(function() {
var options = {
data: tuxinmodcartype.car_companies,
list: {
match: {
enabled: true
}
}
};
$('#company-name-input').easyAutocomplete(options);
});
and I get the error ReferenceError: tuxinmodcartype is not defined
For accessing variables in javascript you can assign them in your controllers with:
Media::addJsDef(array(
'mymodule' => array(
'var1' => 'yes',
'var2' => 'no'
)
));
Then you can use them in your javascript or through console:
let var1 = mymodule.var1;
let var2 = mymodule.var2;
Building javascript files with smarty... I guess it's better to split javascript into more files and load them through controller based on conditions. Or use the above definition for variables to control execution path in your javascript.
Safer way to declare your vars without mymodule array,
Media::addJsDef(array('var1' => $myphpvar));
Media::addJsDef(array('var2' => $myphpvartwo));
this way you DONT need
let var1 = mymodule.var1;
Why this better? Because 'let var1' cause error in iphone safari browser.
You can simply do this in the tpl file:
<script>var = '{$var}';</script>
and use your var in the javascript file.
Source: https://www.prestashop.com/forums/topic/589645-unknown-tag-addjsdef-error/?tab=comments#comment-2490210

Drupal programmatically remove JavaScript

I am trying to disable the JavaScript when the user is using IE. Is there a way to accomplish this in template.php or a custom module?
As alternative to handling the content of $vars['scripts'], which is a string containing the HTML to output in the <head> tag, you could use the value returned from drupal_add_js(NULL, NULL, 'header'), which is similar to the following one:
$header_javascript = array(
'core' => array(
'misc/jquery.js' => array(
'cache' => TRUE,
'defer' => FALSE,
'preprocess' => TRUE,
),
'misc/drupal.js' => array(
'cache' => TRUE,
'defer' => FALSE,
'preprocess' => TRUE,
),
),
'module' => array(),
'theme' => array(),
'setting' => array(
array('basePath' => base_path()),
),
'inline' => array(),
);
The "module" index contains the reference to the JavaScript files added from the modules, "settings" contains all the JavaScript settings generally added by the modules, and "inline" contains inline JavaScript code.
It could help if you need to distinguish between the different JavaScript files, and (for example) not touch any JavaScript file that has been marked as "core."
The counterbalance is that to populate the content of $vars['scripts'] you need to duplicate part of the code used from drupal_get_js(). As you would need a customized code, you would not duplicate all the code of that function, but you still would duplicate part of it.
In Drupal 7, the variable $vars['scripts'] is not passed anymore to template_preprocess_page() (and similar preprocess functions implemented by modules or themes); it is passed to template_preprocess_html().
You can use the preprocess_page() hook in template.php.
function YOUR_THEME_preprocess_page(&$vars) {
if (isset($_SERVER['HTTP_USER_AGENT']) && (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false)) {
$vars['scripts'] = 'get a mac!';
}
}
Obviously you should do something more intelligent with the $vars['scripts'] content :)

JQuery Ajax Get Customization

Using one of the many options defined at http://api.jquery.com/jQuery.ajax/ (or anywhere else) can I map the incoming data to a specific data type rather than the default generic object that is usually returned?
My usual method is to "convert" the generated object by grabbing each property and placing it into the constructor for the new object that I really want to use. Then, I just forget about the old object. I would imagine that there is a much more efficient way to do this.
I came up with/found a few ideas such as simply adding methods to each of the returned objects. It works well, but I just have to know if there is an even more efficient method.
So you're saying that you have code like the following:
function Pirate(name, hasParrot)
{
this.name = name;
this.hasParrot = hasParrot;
}
and the server is sending this JSON data:
{
name: "Blackbeard",
hasParrot: true
}
which jQuery is converting to a plain object, right?
If that's the case, you can use a custom datatype to parse the server's data directly into a Pirate object, like so:
// First define the converter:
jQuery.ajaxSetup({
converters: {
"json pirate": function(obj) {
if(!obj.name || typeof obj.hasParrot === "undefined")
{
throw "Not a valid Pirate object!";
}
else
{
return new Pirate(obj.name, obj.hasParrot);
}
}
}
}
// Then use it!
$.ajax("http://example.com/getPirate", {
data: {id: 20},
dataType: "pirate",
success: function(pirate){
console.log(pirate instanceof Pirate); // Should be true
}
});
Edit: If you really want to skip the step of converting to JSON, you could could replace "json pirate" above with "text pirate" and write your own parser for the raw text returned by the ajax call.

Categories