Djave
Djave

Reputation: 9329

Vue js add click event without using v-on or @click

Is there a way to add a click handler inside a Vue instance without writing on the markup? I'm loading an SVG via ajax, and I'd like to use Vue click events on it.

My Vue file looks like this:

<template>
    <div>
        <div class="map" v-html="map"></div>
    </div>
</template>

<script>
export default{
    data : function(){
        return {
            map : 'Loading'
        };
    },
    methods : {
        getMap : function(){
            var thisMap = this;
            axios.get('/img/world-map.svg').then(function (response) {
                thisMap.map = response.data;
                thisMap.loading = false;
            }).catch(function (error) {
                thisMap.loading = false;
                console.log(error);
            });
        },
    },
    mounted : function(){
        console.log('WorldMap mounted');
        this.getMap();
    }
}
</script>

The issue is that I'm loading a rather large SVG straight into the page. In a perfect world I would just do something like this:

<template>
    <div>
        <div class="map" >
            <svg>
                <g @click="groupClicked" class="asia" id="asia" xmlns:svg="http://www.w3.org/2000/svg">
                  <path stroke="#FFFFFF" d="M715.817,47.266c-4.45,1.25-8.903,2.497-13.357,3.739c-1.074,0.327-8.403,1.757-5.678,3.204
    c-1.922,2.104-2.993,1.568-5.547,1.536c-1.547,1.333,0.981,1.22-0.558,2.421c-0.976,0.761-0.946,1.257-2.106,0.827
    c-0.368-0.136-2.223-0.261-1.543,0.759c2.082,1.3,0.231,3.046-1.466,4.011c-1.831-0.38-3.271-1.611-5.245-1.293
    c-1.229,0.196-2.104,0.763-3.176-0.205c-1.265-1.143,0.371-1.409,1.378-2.177c1.529-1.168,5.473-0.2,2.834-2.668
    c1.061-0.979,2.07-0.946,3.206-1.736c-0.297-0.416-0.649-0.773-1.067-1.068c1.047-1.075,1.679-3.036,3.497-2.725
    c1.441,0.249,2.046-1.318,3.182-2.137c1.121-0.811,2.4-1.266,3.771-1.402c1.656-0.165,3.271,0.134,4.347-1.427
    c0.921-1.334,1.921-1.218,3.468-0.757c1.687,0.504,2.808-0.159,4.442-0.698c2.313-0.118,4.489-0.946,6.812-1.068
    c1.043-1.941,2.354-2.07,4.375-2.331c0.653-0.085,6.433-0.678,4.774,1.792C721.041,46.198,718.024,46.605,715.817,47.266
    C711.364,48.516,718.356,46.505,715.817,47.266z"/>
                </g>
            </svg>
        </div>
    </div>
</template>

However the SVG I'm loading is about 300kb big and I don't want to be carrying that around with all my JavaScript on every page load.

Any comments or solutions welcome.

Edit

Since asking I've actually got quite far with this approach, which isn't perfect but at the moment it seems pretty good.

var vueBus = new Vue({});

$('body').on('click', 'svg g', function(){
    var name = $(this).attr('data-name');
    vueBus.$emit('svgGroupClicked', name);
});

and then adding a listener in my .vue file

mounted() : function(){
    vueBus.$on('svgGroupClicked', function(){ ... });
}

Upvotes: 4

Views: 4717

Answers (1)

thanksd
thanksd

Reputation: 55634

You can just add a click event via plain javascript after the GET request succeeds:

axios.get('/img/world-map.svg').then(function (response) {
  thisMap.map = response.data;
  thisMap.addClickHandler();
  thisMap.loading = false;
})

Your addClickHandler method would look something like this:

methods: {
  addClickHandler: function() {
    var gEl = this.$el.getElementsByTagName('g')[0];
    gEl.addEventListener('click', function() {
      alert('I got clicked');
    });
  },
}

Or, if you're using jQuery:

methods: {
  addClickHandler: function() {
    $(this.$el).find('g')[0].click(function() {
      alert('I got clicked');
    });
  },
}

Upvotes: 2

Related Questions