pagerjs icon indicating copy to clipboard operation
pagerjs copied to clipboard

toJSON issue

Open imrefazekas opened this issue 12 years ago • 11 comments

Dear finnsson,

I got an issue while calling toJSON.

console.log( ko.toJSON( theViewModel ) );

pager.extendWithPage( theViewModel );

console.log( ko.toJSON( theViewModel ) );

The first executed perfectly

{"personal":{"sex":"male", ....

the second console logging fails:

TypeError: JSON.stringify cannot serialize cyclic structures.

How can I use the toJSON of knockout? What do I miss?

Thanks,

Imre

imrefazekas avatar Jul 11 '13 12:07 imrefazekas

I've actually never tried to call ko.toJSON. The error is due to that a page keeps a reference to its parent page while the parent-page keeps a reference to its children (thus cyclic structures). I don't know if there is some way I can instruct ko.toJSON to skip some of these fields. I read at Controlling how an object is converted to JSON that I should probably implement pager.Page.prototype.toJSON. I haven't tried anything but a solution might be

pager.Page.prototype.toJSON = function() {
    return this.ctx;
};

finnsson avatar Jul 11 '13 12:07 finnsson

Wrote a simple test:

<!DOCTYPE html>
<html>
  <head>
    <script src="/js/lib/jquery-2.0.3.min.js"></script>
    <script src="/js/lib/knockout-latest.js"></script>
    <script src="/js/lib/pager.min.js"></script>
  </head>
  <body>
  <script type="text/javascript">
        function AppViewModel() {
            this.firstName = ko.observable("Bert");
            this.lastName = ko.observable("Bertington");

            this.fullName = ko.computed(function() {
                return this.firstName() + " " + this.lastName();
            }, this);

            this.capitalizeLastName = function() {
                var currentVal = this.lastName();   // Read the current value
                this.lastName(currentVal.toUpperCase()); // Write back a modified value
            };
        }

        var theViewModel = new AppViewModel();

        console.log( ko.toJSON( theViewModel ) );

        pager.extendWithPage( theViewModel );

        console.log( ko.toJSON( theViewModel ) );

        ko.applyBindings(new AppViewModel());
    </script>
  </body>
</html>

imrefazekas avatar Jul 11 '13 12:07 imrefazekas

Jepp. It works in that case. I would recommend that you just add

pager.Page.prototype.toJSON = function() {
    return this.ctx;
};

for now. I'll try to add and test it for the 1.1-release.

finnsson avatar Jul 11 '13 12:07 finnsson

OK, thank you.

imrefazekas avatar Jul 11 '13 12:07 imrefazekas

After executing this:

ko.applyBindings(theViewModel);

I receive this Error for toJSON:

Pass a function that returns the value of the ko.computed

imrefazekas avatar Jul 11 '13 13:07 imrefazekas

By executing this:

    theViewModel.toJSON = function() {
        var copy = ko.toJS(this);
        delete copy['$__page__'];
        return copy;
    };

The JSON export seems fine till the applyBindings. After it I receive that message. If I put the pager usage into comments, everything is fine.

imrefazekas avatar Jul 11 '13 14:07 imrefazekas

Here is a complete very small sample what I'm dealing with, hope it helps:

<!DOCTYPE html>
<html>
<head>
    <script src="/js/lib/jquery-2.0.3.min.js"></script>
    <script src="/js/lib/knockout-latest.js"></script>
    <script src="/js/lib/pager.min.js"></script>
</head>
<body>
    <div data-bind="page: {id: 'ignite', title: 'Greetings', role: 'start'}">
        Sportif: <input type="checkbox" data-bind="checked: personal.sportif" />
    </div>
    <script type="text/javascript">
        $(document).ready(function(){
            pager.Page.prototype.toJSON = function() {
                return this.ctx;
            };
            function AppViewModel() {
                this.firstName = ko.observable("Bert");
                this.lastName = ko.observable("Bertington");

                this.fullName = ko.computed(function() {
                    return this.firstName() + " " + this.lastName();
                }, this);

                this.capitalizeLastName = function() {
                    var currentVal = this.lastName();   // Read the current value
                    this.lastName(currentVal.toUpperCase()); // Write back a modified value
                };

                this.personal = {
                    sportif: ko.observable( false )
                };
            }

            var theViewModel = new AppViewModel();

            console.log( '?', ko.toJSON( theViewModel ) );

            pager.extendWithPage( theViewModel );

            console.log( ':', ko.toJSON( theViewModel ) );

            ko.applyBindings( theViewModel );

            console.log( '-', ko.toJSON( theViewModel ) );

            pager.start();

            console.log( '*', ko.toJSON( theViewModel ) );
        });
    </script>
</body>
</html>

And a jsfiddle: http://jsfiddle.net/ndJsk/

Is there anything I can help?

imrefazekas avatar Jul 11 '13 18:07 imrefazekas

The problem is, that after the pager starts, some elements will posses attributes like this:

selectionDirection: [Exception: Error] selectionEnd: [Exception: Error] selectionStart: [Exception: Error]

And here the knockoutJS will fail to generate the JS object so the JSON also. Without the pager, the input field in the test html won't have such exceptions.

imrefazekas avatar Jul 12 '13 08:07 imrefazekas

Commenting out all pager-related code from temp.html and the input element does not have such attributes and knockout runs perfectly.

imrefazekas avatar Jul 12 '13 13:07 imrefazekas

Just made a workaround solution: https://github.com/finnsson/pagerjs/pull/130 Maybe not the best solution but works perfectly for me.

imrefazekas avatar Jul 12 '13 21:07 imrefazekas

Any chance that fix can get merged in and released? I love using ko.toJSON to watch stuff change, and it doesn't work with pager!

mw44118 avatar Jun 19 '15 18:06 mw44118