3

Edited to correct unreported syntax error (see comments). It now works as desired.

I'm having trouble getting my event handler to fire in the following Vue code.

As you see, there are two components, posts and post, and a root Vue instance. The button in the post template should fire the remove event, which is captured by the v-on:remove handler in posts which calls posts.deleteItem with the index of the post. Can someone give me a hint what I'm doing wrong?

    <!DOCTYPE html>
    <html lang="en">
        <head>
        <title>Posts</title>
            <!--link href="../css/bootstrap.css" rel="stylesheet" /-->
        <script src="../vue.js"></script>
        </head>
        <body>
            <div id="app">
                <posts></posts>
            </div>
            <script>
                window.onload = function() {

                    // A post
                    Vue.component('post-item', {
                            props: ['post'],
                            data: function() {
                                return {
                                    editing: false,
                                    _cachedItem: ''
                                }
                            },
                            methods: {
                                deleteItem(postId) {
                                    debugger
                                    this.$emit('remove', event.target.value);
                                },
                            },
                            template: `
                                <div v-on:remove="deleteItem">
                                    <li v-show="!editing">
                                        <p v-html="post.text"></p>
                                            <button v-on:click="$emit('remove')">Delete</button>
                                    </li>
                                </div>
                            `
                    })

                    Vue.component('posts', {
                            data: function() {
                                return {
                                    posts: [
                                        {id: 0, text: "Day at beach"},
                                        {id: 1, text: "Carving the canyons"},
                                        {id: 2, text: "Kickin' it"}
                                    ],
                                };
                            },
                            methods: {
                                deleteItem(index) {
                                    debugger
                                    this.posts.splice(index, 1);
                                }
                            },
                            template: `
                                <div>
                                    <ol>
                                        <post-item
                                                v-for="(post, index) in posts"
                                                v-bind:post="post"
                                                v-bind:key="post.id"
                                                v-on:remove="deleteItem(index)" />
                                    </ol>
                                </div>
                            `
                    });

                    // Root Vue instance
                    new Vue({
                            el: '#app'
                    });

                }
            </script>
        </body>
    </html>
Tom Russell
  • 1,015
  • 2
  • 10
  • 29
  • _"It now works as desired"_ <- looks to me like clicking delete removes all the posts. You need to use `this.posts.splice(postId, 1)` – Phil Sep 26 '18 at 02:11
  • I replaced the code and believe it should now work as long as `vue.js` is in the script's parent directory. – Tom Russell Sep 26 '18 at 02:56

1 Answers1

3

Looks like you're getting a little confused with the event creation and handling.

Events are emitted up to parent components. You don't typically add an event listener within the same component.

All you really need in your post-item component is to emit the remove event with the appropriate data (ie, the post object)

<div>
  <li v-show="!editing">
    <p v-html="post.text"></p>
    <button @click="$emit('remove', post)">Delete</button>
  </li>
</div>    

Then in your parent component (posts), listen for this event on the post-item component and assign the event handler

<post-item v-for="post in posts" :key="post.id" :post="post" @remove="deleteItem" />

and handle the event with post payload

methods: {
  deleteItem (post) {
    this.posts.splice(this.posts.indexOf(post), 1)
  }
}

The post object emitted by the post-item component should be the very same object passed in to its prop which is why you can directly use this.posts.indexOf(post). There's no need to go searching for matching id properties.

Phil
  • 157,677
  • 23
  • 242
  • 245
  • I'm an idiot. There's a misplaced '>' on ``. Looking it over to make your suggested changes helped me spot it. – Tom Russell Sep 26 '18 at 02:06
  • 1
    @TomRussell ah yes, I see it in your question code. That's why I like self-closing tags like in my answer – Phil Sep 26 '18 at 02:08
  • Yes. Still no syntax error but easily-spotted `v-on:remove="deleteItem(post.id)"` on the rendered page. – Tom Russell Sep 26 '18 at 02:14