14

Is this possible to insert to localstorage or is there other way to store this?

$('#pass_to_score').on('click',function(){

var compressed = function(){
    $('.whole_wrap_of_editcriteria').css('display','none');
    $('#wrappler').css('display','block');
    $('#li_addcriteria').css('display','none');
    $('#li_menu1').addClass('active');
    $('#home').removeClass('active');
    $('#menu1').addClass('active');
    $('#title_panel').html('Edit criteria scoring');
}
compressed();
localStorage.setItem('compressed', compressed());
//i also try set as JSON.stringify but its undefined

});
Raffy T Lawrence
  • 315
  • 1
  • 6
  • 18
  • 1
    Possible duplicate of [Storing Objects in HTML5 localStorage](http://stackoverflow.com/questions/2010892/storing-objects-in-html5-localstorage) – eisbehr Aug 12 '16 at 21:14
  • Note that in that specific example what you actually saving in the localStorage is the **result** of the function. – Dekel Aug 12 '16 at 21:15
  • Instead of saving code, you should save data, to be parsed again when needed. – Siguza Aug 12 '16 at 21:15
  • 3
    By using parenthesis after `compressed()` on that `localStorage` line, you're actually executing it and storing the return value (`undefined`). Why do you want to do this? Do you want to keep it in order to execute it later? Explain the use case so we can guide you towards a better solution. – blex Aug 12 '16 at 21:15
  • im trying to save those bunch of code as one, instead of one by one. Even in not order as long as i get every value. And i can execute it all together in localstorage – Raffy T Lawrence Aug 12 '16 at 21:23

2 Answers2

31

I don't know why you'd want that, I would not recommend it, but you can do it using toString.

Store it:

var myFunc = function (){
  alert('Hello world!');
};

// Store it as a String
localStorage.setItem('compressedFunc', myFunc.toString());

Later, retrieve it:

var compressedFunc = localStorage.getItem('compressedFunc');

// Convert the String back to a function
var myFunc = eval('(' + compressedFunc + ')');

// Use it
myFunc();
blex
  • 24,941
  • 5
  • 39
  • 72
  • 1
    This returns an error. `Uncaught SyntaxError: Unexpected token ( at :4:23` – Ruan Carlos Jan 27 '17 at 12:23
  • 1
    @RuanCarlos Thanks, I needed to add parentheses inside the `eval`. This removes the error – blex Sep 26 '17 at 17:53
  • 1
    While it is true this will work (for user-defined functions), it is very insecure, as attackers need only change localStorage with their own function they wish to run. In other words, please do not use code like this in production. – Heretic Monkey Sep 14 '20 at 16:11
5

If you have the function encoded in JavaScript, there would be no need to restore it ever from localStorage, as you already have it available.

You cannot JSON encode a function. You could save the source code of the function, and upon retrieval apply eval to it. But as all know, this has certain risks, captured in the phrase "eval is evil".

You could limit that risk a bit, if you would invent an object structure that closely describes what the function should do. In your case, every statement in the function is a method applied to a jQuery selector. This you could represent with the following object:

var compressed = [
    { selector: '.whole_wrap_of_editcriteria', method: 'css',         args: ['display', 'none'] },
    { selector: '#wrappler',                   method: 'css',         args: ['display', 'none'] },
    { selector: '#li_addcriteria',             method: 'css',         args: ['display','none'] },
    { selector: '#li_menu1',                   method: 'addClass',    args: ['active'] },
    { selector: '#home',                       method: 'removeClass', args: ['active'] },
    { selector: '#menu1',                      method: 'addClass',    args: ['active'] },
    { selector: '#title_panel',                method: 'html',        args: ['Edit criteria scoring'] }
];

Then your actual function, could take that object as its input, and process it, resulting in the same effect:

var applyInstructions = function(instructions) {
    instructions.forEach( cmd => $(cmd.selector)[cmd.method](...cmd.args) );
}

Now, when you want to save this knowledge to localStorage, you only need to store the above constructed object, like so:

// save to localStorage:
localStorage.setItem('compressed', JSON.stringify(compressed));

And after retrieving it, you would execute the generic function on it:

// get from localStorage:
applyInstructions(JSON.parse(localStorage.getItem('compressed')));

This is similar to using eval, but it has the advantage that you can put limits to what can be executed (in applyInstructions). You could for instance check that the method attribute should only be one of the values css, addClass, removeClass, and html, although that last one could be a dangerous one to keep. text would be a better alternative, if possible.

Here is how that safer applyInstructions could look like:

var applyInstructions = function(instructions) {
    if (instructions.some( 
            cmd => ['css','addClass','removeClass','textContent'].indexOf(cmd.method)==-1)) {
        throw "Invalid instructions object";
    }
    instructions.forEach( cmd => $(cmd.selector)[cmd.method](...cmd.args) );
}
trincot
  • 317,000
  • 35
  • 244
  • 286