DonSeba
DonSeba

Reputation: 2119

Replace tag dynamically returns the object instead of the contents

I'm building an chat client and I want to scan the messages for a specific tag, in this case [item:42]

I'm passing the messages one by one to the following component:

<script>
import ChatItem from './ChatItem'

export default {
    props :[
        'chat'
    ],

    name: 'chat-parser',

    data() {
        return {
            testData: []
        }
    },

    methods : {
        parseMessage(msg, createElement){
            const regex = /(?:\[\[item:([0-9]+)\]\])+/gm;
            let m;

            while ((m = regex.exec(msg)) !== null) {
                msg = msg.replace(m[0],
                    createElement(ChatItem, {
                        props : {
                            "id" : m[1],
                        },
                    }))


                if (m.index === regex.lastIndex) {
                    regex.lastIndex++;
                }
            }


            return msg
        },

    },

    render(createElement) {
        let user = "";
        let msg  = this.parseMessage(this.$props.chat.Message, createElement)

        return createElement(
            'div',
            {

            },
            [
                 // "hello",// createElement("render function")
                createElement('span', '['+ this.$props.chat.Time+'] '),
                user,
                msg,
            ]
        )

    }
};

</script>

I thought passing createElement to the parseMessage method would be a good idea, but it itsn't working properly as it replaces the tag with [object object]

The chatItem looks like this :

<template>
    <div>
        <span v-model="item">chatITem : {{ id }}</span>
    </div>
</template>

<script>
    export default {
        data: function () {
            return {
                item : [],
            }
        },

        props :['id'],

        created() {
            // this.getItem()
        },

        methods: {
             getItem: function(){
               obj.item = ["id" : "42", "name": "some name"]
             },

        },
    }
</script>

Example :

if the message looks like this : what about [item:42] OR [item:24] both need to be replaced with the chatItem component

Upvotes: 1

Views: 57

Answers (1)

skirtle
skirtle

Reputation: 29132

While you can do it using a render function that isn't really necessary if you just parse the text into a format that can be consumed by the template.

In this case I've kept the parser very primitive. It yields an array of values. If a value is a string then the template just dumps it out. If the value is a number it's assumed to be the number pulled out of [item:24] and passed to a <chat-item>. I've used a dummy version of <chat-item> that just outputs the number in a <strong> tag.

new Vue({
  el: '#app',
 
  components: {
    ChatItem: {
      props: ['id'],
      template: '<strong>{{ id }}</strong>'
    }
  },

  data () {
    return {
      text: 'Some text with [item:24] and [item:42]'
    }
  },
  
  computed: {
    richText () {
      const text = this.text

      // The parentheses ensure that split doesn't throw anything away
      const re = /(\[item:\d+\])/g

      // The filter gets rid of any empty strings
      const parts = text.split(re).filter(item => item)
      
      return parts.map(part => {
        if (part.match(re)) {
          // This just converts '[item:24]' to the number 24
          return +part.slice(6, -1)
        }
        
        return part
      })
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
  <template v-for="part in richText">
    <chat-item v-if="typeof part === 'number'" :id="part"></chat-item>
    <template v-else>{{ part }}</template>
  </template>
</div>

If I were going to do it with a render function I'd do it pretty much the same way, just replacing the template with a render function.

If the text parsing requirements were a little more complicated then I wouldn't just return strings and numbers. Instead I'd use objects to describe each part. The core ideas remain the same though.

Upvotes: 1

Related Questions