1

I'm using Material Design's Vue component icon set. I'd like to process a string to include an icon in the middle.

Input (a string I can't control):

"I want an icon to go there"

Desired output:

"I want an <timer-icon></timer-icon> to go there"

I'm trying to do this using a method that processes the text. But how can I get my icon component in there?

I've tried this:

<template>
    <span>{{ insertIcon(myString) }}</span>
</template>

import TimerIcon from 'vue-material-design-icons/Timer.vue'

export default {
   data () {
      return {
        myString: fromAnotherPlugin // "I want an icon to go there"
      }
   },
   components: {
      TimerIcon
   },
   methods: {
      insertIcon: function (string) {
         return string.replace('icon', TimerIcon)
      }
   }
}

But it returns [object Object] in place of "icon."

I've also tried referencing the component as HTML.

<template>
    <span>{{ insertIcon(myString) }}</span>
</template>

import TimerIcon from 'vue-material-design-icons/Timer.vue'

export default {
   data () {
      return {
          myString: fromAnotherPlugin // "I want an icon to go there"
      }
   },
   components: {
      TimerIcon
   },
   methods: {
      insertIcon: function (string) {
         return string.replace('icon', '<TimerIcon></TimerIcon>')
      }
   }
}

But it comes back empty.

3
  • you need to register new component, components: { MenuIcon } and when using it don't use PascalCase use kebab-case like so <timer-icon /> Commented Sep 27, 2018 at 21:32
  • You cannot replace a component into a string. A component is an object. Are you trying to render the icon into your template? If so then you can use dynamic components to do that. Commented Sep 28, 2018 at 1:55
  • @fila90 Thanks, I omitted that from the question when I was simplifying my code but it was in the original. I've updated that here. Commented Sep 28, 2018 at 3:37

2 Answers 2

4

I figured this out based on this tutorial and a suggestion from Justin Kahn. You must create an instance of the component and then you can access the output and other properties.

1) Import Vue and the component into your page:

import Vue from 'vue'
import TimerIcon from 'vue-material-design-icons/Timer.vue'

2) Create an instance of your component

const ComponentClass = Vue.extend(TimerIcon)
const instance = new ComponentClass()

3) Mount and then output the innerHTML on an instance within the function

  insertIcon: function (string) {
      const myicon = instance.$mount()
      const myiconhtml = myicon.$el.innerHTML
      return string.replace('icon', myiconhtml)
  }

The $el object includes other properties, but the innerHTML has what I needed.

Sign up to request clarification or add additional context in comments.

Comments

0

If you know what the component is going to be you could just toggle that component using v-if inside your template

<template>
  ... other stuff
  <TimerIcon v-if="showTimer" />
</template>

If you do not want to couple your template to a specific component, you can pass the component down and use v-bind:is or just :is

<component :is="TimerIcon"> </component>

source: https://v2.vuejs.org/v2/api/#component

5 Comments

Thanks for your help. I'm basically processing a string I can't control and trying to insert an icon into it. I've edited the question a bit to clarify. I don't think the solution you proposed would work because I need the icon inside the string that's been supplied.
Where is the string that is supplied supposed to be rendered?
It's a string generated by another plugin (moment.js calendar string). There are other workarounds but I was trying to add the component result in some programmatic way so I didn't have to do trickier string modification. Perhaps that's not possible.
I think you could render the TimerIcon using createElement, convert to HTML markup and then replace like you are currently doing. Any interactivity would get lost, but this will work fine for simple display components.
Thanks, this turned me onto the right information and I found a way. I'll post and accept the answer, but if you want to update yours to include please do.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.