26

Sup people!

I got this HTML code here:

// index.html
<div data-init="component-one">
  <...>

 <div data-init="component-two">
   <button @click="doSomething($event)">
 </div>
</div>

This basically references a Vue instance inside another Vue instance if I understood everything correctly. The respective JS code is split up in two files and looks like this:

// componentOne.js
new Vue(
  el: '[data-init="component-one"]',
  data: {...},
  methods: {...}
);


// componentTwo.js
new Vue(
  el: '[data-init="component-two"]'
  data: {...}
  methods: {
    doSomething: function(event) {...}
  }
);

Now, the problem with this is, that doSomething from componentTwo never gets called.

But when I do some inline stuff, like {{ 3 + 3 }}, it gets computed like it should. So Vue knows there is something. And it also removes the @click element on page load.

I tried fiddling around with inline-template as well, but it doesn't really work as I'd expect it to in this situation. And I figured it isn't meant for this case anyway, so I dropped it again.

What would the correct approach be here? And how can I make this work the easiest way possible with how it's set up right now?

The Vue version we use is 2.1.8.

Cheers!

4
  • Not sure, if it could help, but you've tried to add the subcomponent via "components: [childcomponent]" ?? Commented Mar 7, 2017 at 11:11
  • I'm wonder why you have 2 Vue instances, instead of creating one main instance and one component which would fit better in your case. If you create componentTwo as a real component, then you can emit event from child to root intance and catch it there. Commented Mar 7, 2017 at 12:18
  • Perhaps you should use componentOne.vue and componentTwo.vue instead. Read vuejs.org/v2/guide/components.html Commented Mar 7, 2017 at 12:32
  • Can you jsfiddle this? Commented Apr 29, 2017 at 2:55

6 Answers 6

14

The problem is that you have two vue instances nested to each other. If the elements are nested, then you should use the same instance or try components

https://jsfiddle.net/p16y2g16/1/

// componentTwo.js
var item = Vue.component('item',({
  name:'item',
    template:'<button @click="doSomething($event)">{{ message2 }</button>',
    data: function(){
      return{ 
        message2: 'ddddddddddd!'
    }},
  methods: {
    doSomething: function(event) {alert('s')}
  }
}));

var app = new Vue({
  el: '[data-init="component-one"]',
  data: {
    message: 'Hello Vue!'
  }
});

<div data-init="component-one">
  <button >{{ message }}</button>
  <item></item>
</div>

Separate instances work if they are independant of each other. as follows:

https://jsfiddle.net/p16y2g16/

var app = new Vue({
  el: '[data-init="component-one"]',
  data: {
    message: 'Hello Vue!'
  }
});

// componentTwo.js
var ddd = new Vue({
  el: '[data-init="component-two"]',
    data: {
      message: 'ddddddddddd!'
    },
  methods: {
    doSomething: function(event) {alert('s')}
  } 
});
Sign up to request clarification or add additional context in comments.

Comments

7

But when I do some inline stuff, like {{ 3 + 3 }}, it gets computed like it should. So Vue knows there is something.

Because you have parent instance 'componentOne'. It activated Vue for this template. If you need to set another instance inside, you have to separate part of template. Example (it can lag in snippet!) . Alternative

https://jsfiddle.net/qh8a8ebg/2/

// componentOne.js
new Vue({
  el: '[data-init="component-one"]',
  data: {
  	text: 'first'
  },
  methods: {}
});


// componentTwo.js
new Vue({
  el: '[data-init="component-two"]',
  data: {
  	text: 'second'
  },
  template: `<button @click="doSomething($event)">{{text}}</button>`,
  methods: {
    doSomething: function(event) {
    	console.log(event);
    }
  }
});
<script src="https://vuejs.org/js/vue.min.js"></script>
<div data-init="component-one">
{{text}}
</div>
 <div data-init="component-two">
 </div>

1 Comment

this is exactly the solution what I was searching for past two days. Thanks man
0

The button element inside component-two is referenced as a slot in Vue. The evaluation of the @click directive value happens in the parent component (component-one, which host component-two). Therefor, you need to declare the click handler over there (over component-one).

If you want the handler to be handled inside component-two, you should declare a click directive for the slot element in it's (component-two) template, and pass the handler function, for instance, as a pop.

good luck.

Comments

0

You're doing everything right except you've nested the 2nd Vue instance inside the 1st. Just put it to the side and it will work as expected.

Vue ignores binding more than once to the same element to avoid infinite loops, which is the only reason it doesn't work nested.

Comments

-1

Use vue-cli to create a webpack starter app. vue init app --webpack

Then, try to structure your components this way. Read more: https://v2.vuejs.org/v2/guide/components.html#What-are-Components

  1. This is main.js

import Vue from 'vue'
import ComponentOne from './ComponentOne.vue'
import ComponentTwo from './ComponentTwo.vue'

new Vue({
  el: '#app',
  template: '<App/>',
  components: { 
    ComponentOne,
    ComponentTwo
  }
})

  1. This is ComponentOne.vue

<template>
  <div class="user">
    <div v-for="user in users">
      <p>Username: {{ user.username }}</p>
    </div>
  </div>
</template>


<script>
export default {
  data () {
    return {
      users: [
        {username: 'Bryan'},
        {username: 'Gwen'},
        {username: 'Gabriel'}
      ]
    }
  }
}
</script>

  1. This is ComponentTwo.vue

<template>
  <div class="two">
    Hello World
  </div>
</template>


<script>
export default {

}
</script>

4 Comments

This would work only if he is working with Single File Component and use/have configured webpack or browserify with coresponding loaders. There is a global api for component registration Vue.component('name', {}) which will work too.
That's true, I miss this out!
Thank you for this snippet, it looks quite elegant! We actually have Webpack and everything set up. The unusual code organization is just because I'm quite new to advanced Vue stuff. I didn't find the time to try it out and refactor today. I'll update and accept as soon as it's done and working!
Try to use vue-cli to create that webpack starter app vue init app --webpack
-2
<div th:if="${msg.replyFloor}">
    <div class="msg-lists-item-left">
        <span class="msg-left-edit"
              th:classappend=" ${msg.unreadCount == 0} ? 'msg-all-read' ">您在</span>
        <span th:text="${msg.topic.title}"
              class="msg-left-edit-res"
              th:classappend=" ${msg.unreadCount == 0} ? 'msg-all-read' ">问题回答</span>
        <span th:text="${msg.type.name}"
              class="msg-left-edit "
              th:classappend=" ${msg.unreadCount == 0} ? 'msg-all-read' ">帖子相关</span>
        <span class="msg-left-edit-number" >
            产生了<span th:text="${msg.unreadCount} ? : ${msg.unreadCount} + '条新' : ${msg.unreadCount} + '条' "
                       th:class="${msg.unreadCount} ? : 'number-inner':''">2132条</span>回复
        </span>
    </div>
    <div class="msg-lists-item-right">
        <span th:text="${msg.lastShowTime}">2017-8-10</span>
    </div>
</div>

1 Comment

give enough explanation for your answers so it will be help full them to get better understanding about the answer and how to solve this problem in future. See the link to know how to write good answers.

Your Answer

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