Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Method of destroying morris instance? #569

Open
atwoodhouse opened this issue Mar 12, 2015 · 15 comments
Open

Method of destroying morris instance? #569

atwoodhouse opened this issue Mar 12, 2015 · 15 comments

Comments

@atwoodhouse
Copy link

This is my first post ever at Github!

I'd really like to use Morris.js for a project of mine, however I'm stuck at one critical point.

My web app does not use traditional page loads, but instead uses ajax to empty the content of the main container, and fill it with the content of the page that should be loaded. When that's done it executes a js function for that specific page, which does different things for different pages.

On one page I'm using a morris graph. (so far just a test graph) The page to be loaded looks like this:

        <div class="row">
            <div class="col-lg-2 col-md-2 col-sm-3 col-xs-4">
                <a id="timeSpan" class="btn btn-primary graphBtn">Last 24 hours</a>
                <a class="btn btn-primary graphBtn">A</a>
                <a class="btn btn-primary graphBtn">B</a>
                <a class="btn btn-primary graphBtn">C</a>
            </div>
            <div class="col-lg-10 col-md-10 col-sm-9 col-xs-8">
                <div id="test-stats" style="height: 400px"></div>
            </div>
        </div>

The function that is run on page load is the following:

    function pageload_dashboard(){
        window.morrisObj = new Morris.Line({
            // ID of the element in which to draw the chart.
            element: 'test-stats',
            // Chart data records -- each entry in this array corresponds to a point on
            // the chart.
            data: [
                { year: '2010', value: 20 },
                { year: '2011', value: 10 },
                { year: '2012', value: 5 },
                { year: '2013', value: 5 },
                { year: '2014', value: 20 }
            ],
            // The name of the data record attribute that contains x-values.
            xkey: 'year',
            // A list of names of data record attributes that contain y-values.
            ykeys: ['value'],
            // Labels for the ykeys -- will be displayed when you hover over the
            // chart.
            labels: ['Value'],
            resize: true
        });
    }

The ajax call that does all the magic looks like this:

        $(function(){
            $( "#main-nav li" ).click(function() {
                var self = $(this);
                var pageToLoad = self.attr('id').replace('nav-', '');
                $.ajax({
                    url: '/_'+pageToLoad,
                    type: 'GET',
                    success: function(resp)
                    {
                        resp_data = JSON.parse(resp);
                        window.morrisObj = NaN; /*unload morris*/
                        $("#main-nav>li.active").removeClass("active");
                        self.addClass("active");
                        $("#main-container").html(resp_data['page']);
                        pageload[pageToLoad]();
                    }
                });
            });
        });

As you can see I'm trying to kill/unload any morrisObj that might exist with the following line in my ajax code:

                        window.morrisObj = NaN; /*unload morris*/

This method does not work. After a couple of loads back and forth, morris.js is working so hard that it stops responding to the point where I have to reboot my computer.

I've really tried to google my way out of this one, but I can't seem to find anyway of killing a morris instance.

Tl;dr: How do I destroy a morris instance properly?

@atwoodhouse
Copy link
Author

I just noticed that the reason for the crashes appear to be the following (awesome) option:

            resize: true

After a tab switch, and upon window resize (or inspect element, which sort of resizes the window) - that's when everything crashes.

I've temporarily switched off resize and things work smoothly. However, unresponsive charts are pretty useless 2015.

Is there anyway to unbind the resize: true setting?

@atwoodhouse
Copy link
Author

Solved:

$(window).off('resize');
window.morrisObj = NaN;

Still interested in official ways of killing responsive morris instances. Anyone?

@leriel
Copy link
Contributor

leriel commented Mar 19, 2015

Looking at the code, there doesn't appear to be any other way to do this currently

If the resize handler wrapper (

$(window).bind 'resize', (evt) =>
) was bound to variable, you could deregister it, without globally disabling resize event.

However, that is not the case. handler wrapper is anonymous and it would be hack solution anyway.

I'm not sure if this is the only case, when morris binds globally to an event - anyway as you showed above, there is need for clean destroy method. I think issue is still valid and it's best to reopen it.

@atwoodhouse atwoodhouse reopened this Mar 19, 2015
@atwoodhouse
Copy link
Author

Thanks for your response, leriel!

I've now reopened the issue. Let's hope for a less hacky solution!

@mastef
Copy link

mastef commented Jul 18, 2015

window.morrisObj.destroy() would be great... especially when using morris with e.g. modals, just to clean up after closing them. Even setting it to NaN the event handlers are still listening

@Thesephi
Copy link

I got the same issue when I was trying to use Morris charts in a singple-page setup. After removing the chart DOMs, we get some javascript errors owing to the window object still retaining the resize event handlers.

One possible way to fix this is to use jQuery's event namespaces, i.e. calling $(window).bind('resize.morris', handler) rather than $(window).bind('resize', handler), then when we need to destroy the charts, we can call $(window).unbind('resize.morris') to safely remove the event listeners specific to Morris charts (and not the event listeners registered elsewhere).

@mastef
Copy link

mastef commented Sep 23, 2015 via email

@denisrpriebe
Copy link

I solved my issue by simply calling $('#chart').empty(); where #chart is the id of the element which contains your chart or graph. The .empty() function removes other constructs such as data and event handlers from the child elements before removing the elements themselves. After calling the above method I then reinitialized morris.

@lbolanos
Copy link

I solved my problem adding this to morris.js after function Grid(options), and calling it properly before delete the object.

Grid.prototype.destroy = function() {
    $(this.el).unbind('mouseleave');
    $(this.el).unbind('mousemove');
    $(this.el).unbind('touchstart touchmove touchend');
    $(this.el).unbind('click');
    $(this.el).unbind('mouseup');
    $(this.el).unbind('mousedown');
    $(this.el).unbind('resize');        
};

@ItalloSan
Copy link

lbolanos cheers - just what I needed.

@kamil-kielczewski
Copy link

I little change above solution to clear also svg element (if we don't do it on reset chart, the new and old chart and svg elements will be still visible...):

    Grid.prototype.destroy = function() {
      this.raphael.remove();
      $(this.el).unbind('mouseleave');
      $(this.el).unbind('mousemove');
      $(this.el).unbind('touchstart touchmove touchend');
      $(this.el).unbind('click');
      $(this.el).unbind('mouseup');
      $(this.el).unbind('mousedown');
      $(this.el).unbind('resize');
    };

@priyankamalviya
Copy link

priyankamalviya commented Apr 17, 2017

@lbolanos Could you please tell me where should I call destroy function in morris.js?

@beaver71
Copy link

beaver71 commented May 9, 2017

Another integration to destroy() method in order to remove also hover tooltips:

    Grid.prototype.destroy = function() {
      this.raphael.remove();
      $(this.el).find('.morris-hover').remove();
      $(this.el).unbind('mouseleave');
      $(this.el).unbind('mousemove');
      $(this.el).unbind('touchstart touchmove touchend');
      $(this.el).unbind('click');
      $(this.el).unbind('mouseup');
      $(this.el).unbind('mousedown');
      $(this.el).unbind('resize');
    };

So the method is exposed to all chart types; for example:

      var mychart = Morris.Line({
            element: 'my-chart',
            data: data,
            xkey: 'x',
            ykeys: [...],
            labels: [...],
            lineColors: ['#e69e61']
       });

So mychart .destroy(); will remove the chart

@ajoslin103
Copy link

When I used the " $('#chart').empty(); " solution it broke the hover labels

Using the " destroy() " method preserved the hover functionality

I had to attach the destroy() to the Grid inside the Morris

Morris.Grid.prototype.destroy = function () { ... };

@pierresh
Copy link

@ajoslin103 You can check my fork, it includes a built-in destroy function
pierresh#6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests