-1

I am using Node where I have JavaScript object literals with methods in the backend, e.g.:

const report = {
    id: 1,
    title: 'Quarterly Report for Department 12345',
    abstract: 'This report shows the results of the sales and marketing divisions.', 
    searchText: function () {
        return this.title + '|' + this.abstract;
    }
};

And I want to send these object literals to the frontend via AJAX and be able to call the methods on these objects as I can in the backend.

But even though I can send the objects to the frontend without JSON.stringify(), they are still converted to plain JSON by the time they reach my frontend:

enter image description here

Am I missing something, or is there not a way to send full object literals from backend to frontend. I'm using Axios.

Edward Tanguay
  • 189,012
  • 314
  • 712
  • 1,047
  • You can't. JSON doesn't store functions. You'll need to create a client side script that handles that when you receive this JSON, when you receive the JSON you can attach the function onto it. – Adrian Aug 08 '19 at 10:21
  • everything you send/get via AJAX (and litterally every mean of communication) is converted to a string somewhere so you can't just send an object litteral. the best way to communicate js objects is to use JSON which doesn't allow function – jonatjano Aug 08 '19 at 10:23
  • I assume your library just hides the call to `JSON.stringify()`. So you're still bound to the limitation of JSON not supporting functions. One approach might be to separate data from functionality. So have, e.g., a class containing the functionality and submit only the data in JSON. On the client side instantiate that class with the submitted values, so you can use the functionality. – Sirko Aug 08 '19 at 10:23
  • Even with `JSON.stringify()` and then parse you won't be able retrieve back your function definition. – ambianBeing Aug 08 '19 at 10:24
  • Sirko is on the right track here. Separate code from data. You send data from the server to the client. The code needs to be in the client already and you then create an object of the right type in the client and give it the data that you got from the server for it to initialize itself. If the object might be of varying type, then part of the data would be an identifier that says what type of object should be created for this data. – jfriend00 Aug 08 '19 at 10:26

1 Answers1

1

But even though I can send the objects to the frontend without JSON.stringify(),

It sounds like you are using JSON.stringify … just indirectly (via a library).

JSON has no function data type. So you can't just use JSON.

You have a few options.

Listed in the order I'd recommend them in.


Resolve the methods

In your example, your function simple return this.title + '|' + this.abstract; so you could replace it with a string:

const report = {
    id: 1,
    title: 'Quarterly Report for Department 12345',
    abstract: 'This report shows the results of the sales and marketing divisions.', 
    searchText: 'Quarterly Report for Department 12345|This report shows the results of the sales and marketing divisions.'
    }
};

You could use the replacer argument of JSON.stringify to do this automatically for any method on the object.

This is the simplest option but results in data that doesn't update dynamically so it might not be suitable for your needs.

Add the methods with client-side code

Send a simple object which doesn't have the method but does have a field which describes the type of object it does.

Then inflate it on the client:

const type = ajaxResponse.type;
const Constructor = collectionOfConstructorFunctions[type];
const data = new Constructor(ajaxResponse.data);

Send JavaScript instead

You could use JSONP instead of Axios.

The response would be application/javascript instead of application/json so you could encode function expressions in the returned data.

I don't recommend this option.

Encode the functions in the JSON and then include them client-side

This is horrible.

const report = {
    id: 1,
    title: 'Quarterly Report for Department 12345',
    abstract: 'This report shows the results of the sales and marketing divisions.',
    searchText: "return this.title + '|' + this.abstract;"
}

and then, on the client:

report.searchText = new Function(report.searchText);
console.log(report.searchText());

This is effectively using eval. Don't do it.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335