Bootstrap: Tooltip.destroy() is missing a null check for that.$element

Created on 24 Jan 2017  路  7Comments  路  Source: twbs/bootstrap

Tooltip.destroy() is missing a null check for that.$element. Without it a

Uncaught TypeError: Cannot read property 'off' of null

may result.

Using: Chrome 55, JQuery 3.1.1, Bootstrap 3.3.7

I inserted the code below which fixed the issue:

      if (that.$element == null) {
        console.error("bootstrap-3.3.7.js:1736  Tooltip.destroy()  element is null");
        return;
      }

This is how it looks in complete form:

  Tooltip.prototype.destroy = function () {
    var that = this
    clearTimeout(this.timeout)
    this.hide(function () {
      if (that.$element == null) {
        console.error("bootstrap-3.3.7.js:1736  Tooltip.destroy()  element is null");
        return;
      }
      that.$element.off('.' + that.type).removeData('bs.' + that.type)
      if (that.$tip) {
        that.$tip.detach()
      }
      that.$tip = null
      that.$arrow = null
      that.$viewport = null
      that.$element = null
    })
  }

bootstrap_bug

NOTE: The line numbers in bootstrap-3.3.7.js may be slightly off as my local copy had the above change in place. The stack trace should be correct though.

js v3

Most helpful comment

This error is in the bootstrap.js file. To fix this error, open this file and look for lines 998-1004:

var complete = function () {
        var prevHoverState = that.hoverState
        that.$element.trigger('shown.bs.' + that.type)
        that.hoverState = null

        if (prevHoverState == 'out') that.leave(that)
      }

and change to:

var complete = function () {
        var prevHoverState = that.hoverState
        null!=that.$element && that.$element.trigger('shown.bs.' + that.type)
        that.hoverState = null

        if (prevHoverState == 'out') that.leave(that)
      }

Look for lines 1240-1253 lines:

Tooltip.prototype.destroy = function () {
    var that = this
    clearTimeout(this.timeout)
    this.hide(function () {
      that.$element.off('.' + that.type).removeData('bs.' + that.type)
      if (that.$tip) {
        that.$tip.detach()
      }
      that.$tip = null
      that.$arrow = null
      that.$viewport = null
      that.$element = null
    })
  }

and change to:

Tooltip.prototype.destroy = function () {
    var that = this
    clearTimeout(this.timeout)
    this.hide(function () {
      null!=that.$element && that.$element.off('.' + that.type).removeData('bs.' + that.type)
      if (that.$tip) {
        that.$tip.detach()
      }
      that.$tip = null
      that.$arrow = null
      that.$viewport = null
      that.$element = null
    })
  }

All 7 comments

Support for v3 has mostly ceased. Please let us know if this issue affects v4.
See : https://github.com/twbs/bootstrap/issues/20631

Hi. I am also facing the same issue. I am using the above solution. If it is not going to be in boosttrap 3.3.7, is it going to be in v4?

I'm not sure this issue is present in V4, but as I said if this issue affects V4 let us know, thank you

Not sure if it's worth mentioning, but downgrading to bootstrap-3.3.6.js resolved this exact issue for me, hope it gives others an option to try before moving to v4 :)

Hi. I am also facing the same issue and this is my fix $('.tooltip').tooltip('destroy').remove();

This error is in the bootstrap.js file. To fix this error, open this file and look for lines 998-1004:

var complete = function () {
        var prevHoverState = that.hoverState
        that.$element.trigger('shown.bs.' + that.type)
        that.hoverState = null

        if (prevHoverState == 'out') that.leave(that)
      }

and change to:

var complete = function () {
        var prevHoverState = that.hoverState
        null!=that.$element && that.$element.trigger('shown.bs.' + that.type)
        that.hoverState = null

        if (prevHoverState == 'out') that.leave(that)
      }

Look for lines 1240-1253 lines:

Tooltip.prototype.destroy = function () {
    var that = this
    clearTimeout(this.timeout)
    this.hide(function () {
      that.$element.off('.' + that.type).removeData('bs.' + that.type)
      if (that.$tip) {
        that.$tip.detach()
      }
      that.$tip = null
      that.$arrow = null
      that.$viewport = null
      that.$element = null
    })
  }

and change to:

Tooltip.prototype.destroy = function () {
    var that = this
    clearTimeout(this.timeout)
    this.hide(function () {
      null!=that.$element && that.$element.off('.' + that.type).removeData('bs.' + that.type)
      if (that.$tip) {
        that.$tip.detach()
      }
      that.$tip = null
      that.$arrow = null
      that.$viewport = null
      that.$element = null
    })
  }

Just a comment on the error in case it still happens for other people:
destroy() must only be called once. Calling it twice, will result in this error.

As can be seen in the code, that.$element is set to null at the end of the function. Thus if you see the error, something in your code is highly likely to call the destroy() function twice.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alvarotrigo picture alvarotrigo  路  3Comments

ghost picture ghost  路  3Comments

vinorodrigues picture vinorodrigues  路  3Comments

IamManchanda picture IamManchanda  路  3Comments

devdelimited picture devdelimited  路  3Comments