Leaflet.EasyButton icon indicating copy to clipboard operation
Leaflet.EasyButton copied to clipboard

Change button state icon at runtime

Open Diferno opened this issue 3 years ago • 3 comments

Hi! I have a button with 3 states and want to refresh the 3rd state's icon with the count of features retrieved from backend. So far I've tried updating the button.option.state[2].icon in a watcher, but... although the components option have been changed, the button itself doesn't refresh.

Any tips on how to force that refresh?

      const _this = this
      this.searchInArea = this.$leaflet.easyButton({
        states: [{
          stateName: 'search',
          icon: `<i class="mdi mdi-map-search search-in-zone-btn text-primary">${this.$t('searchInZone')}</i>`,
          title: _this.$t('searchInZone'),
          onClick: (btn, map) => {
            btn.state('loading')
            _this.loadFeatures()
              .then(() => {
                btn.state('loaded')
              })
          }
        }, {
          stateName: 'loading',
          icon: `<i class="search-in-zone-btn mdi mdi-loading mdi-spin">${this.$t('loading')}</i>`
        }, {
          stateName: 'loaded',
          icon: `<i class="search-in-zone-btn">Showing ${_this.layerFeatures.length} features</i>`
        }]
      })

(....)

watch: {
    layerFeatures() {
          if (this.layerFeatures) {
            this.searchInArea.options.states.find(st => st.stateName === 'loaded').icon = `<i class="search-in-zone-btn">Showing ${this.layerFeatures.length} features</i>`
          }
        }
}

Diferno avatar Nov 16 '21 09:11 Diferno

I'd probably create an empty div for the third state and update it as you would with any other dom element

      const _this = this
      this.searchInArea = this.$leaflet.easyButton({
        states: [{
          stateName: 'search',
          icon: `<i class="mdi mdi-map-search search-in-zone-btn text-primary">${this.$t('searchInZone')}</i>`,
          title: _this.$t('searchInZone'),
          onClick: (btn, map) => {
            btn.state('loading')
            _this.loadFeatures()
              .then(() => {
                btn.state('loaded')
              })
          }
        }, {
          stateName: 'loading',
          icon: `<i class="search-in-zone-btn mdi mdi-loading mdi-spin">${this.$t('loading')}</i>`
        }, {
          stateName: 'loaded',
          icon: `<div id="feature-count-container"></div>`
        }]
      })

const featureCount = document.getElementById('feature-count-container');

watch: {
    layerFeatures() {
          if (this.layerFeatures) {
            featureCount.innerHTML = `<i class="search-in-zone-btn">Showing ${this.layerFeatures.length} features</i>`
          }
        }
}

Let me know if this presents any issues or you have any other questions

atstp avatar Dec 06 '21 16:12 atstp

Thx for the answer, but I may be doing something wrong, cause the feature-count-container div can't be found in the DOM.

Is it created even if the initial state is not itself? (currently the initial state is 'search')

Diferno avatar Mar 21 '22 11:03 Diferno

Ah, I see. The icon element is created when you initialize the easyButton, but document.getElementById will only find elements that are attached to the document.

What framework/library handles the watch function?

this is a bit hacky, but I think it should get things working for you:

// switch states to attach the icon to the document
this.searchInArea.state('loaded');

// search the dom and grab a reference to the element
const featureCount = document.getElementById('feature-count-container');

// switch back to the default state
this.searchInArea.state('search');

atstp avatar Mar 29 '22 03:03 atstp