Stimulus Discourse

this.element.outerHTML not catching up changes


#1

Hello!

I’m trying to create a simple “Follow me” button using rails and Stimulus (1.1). Simplified HTML markup for it is as follows:

a.btn.btn-wider.btn-sm(data-controller="follow-btn"
                       data-follow-btn-action-path=toggle_follow_api_ujs_account_path(presenter.account)
                       data-follow-btn-following=presenter.following?.to_s
                       data-action="click->follow-btn#toggle")

  | Follow me

Stimulus controller looks like this:

import BaseController from "./base_controller"
import axios from 'axios'

export default class extends BaseController {
  initialize () {
  }

  toggle () {
    let req = axios.post(this.data.get('actionPath'))

    req.then((resp) => {
      this.element.outerHTML = resp.data
      console.log(this.following) # <== this returns the previous attribute value!
    })
  }

  get following () {
    return this.data.get('following')
  }
}

And basically, after using this.element.outerHTML (is that even a “legal” approach?), this.data.get returns values from before the outerHTML swap. Am i doing something wrong in here or is that known and reasonable behavior?

Thanks in advance!


#2

Setting an element’s outerHTML removes it from the DOM, which will disconnect() its controller instance. I assume your resp.data HTML contains similar markup with data-controller="follow-btn"? If so, then a new controller instance will be created.

Try logging the complete lifecycle:

let id = 0

export default class extends BaseController {
  initialize() {
    this.id = id++
    console.log("initialize", this.id)
  }

  connect() {
    console.log("connect", this.id)
  }

  disconnect() {
    console.log("disconnect", this.id)
  }
}

If you want to keep the same controller instance alive, set innerHTML instead.