Vue broadcast example using store

by ktsn

HTML

<script src="https://npmcdn.com/vue/dist/vue.js"></script>

<div id="app">
  <ul>
      <item v-for="child in treeData"
        :model="child">
      </item>
  </ul>
</div>
<script type="text/x-template" id="item-template">
  <li>
  	<label>
    	<input type="checkbox" :checked="model.value" @change="onChange" />
      {{model.label}}
    </label>
  	
    <ul v-if="model.children">
      <item v-for="child in model.children"
        :model="child">
      </item>
    </ul>
  </li>
</script>

Babel + JSX

const store = new Vue({
  data: {
  	root: {
      children: [
        {
          id: '1',
          label:'A',value:false,
          children:[
            {
              id: '1.1',
              label:'A-1',value:false,
              children:[
                {id: '1.1.1', label:'A-1-1', value:false},
                {id: '1.1.2', label:'A-1-2', value:false}
              ]
            },
            {id: '1.2', label:'A-2', value:false}
          ]
        },
        {
          id: '2',
          label:'B',value:false,
          children:[
            {id: '2.1', label:'B-1', value:false},
            {id: '2.2', label:'B-2', value:false}
          ]
        }
      ]
    }
  },
  
  methods: {
  	// 再帰的に子孫に値を伝搬させる
  	walk: function(target, val) {
      target.value = val
      
      if (!target.children) return
      
      target.children.forEach((child) => {
        this.walk(child, val)
      })
    }
  },
  
  events: {
  	'change-at-parent': function(id, val) {
    	// 対象となる sub tree を探す
      const path = id.split('.')
      const target = path
      	.map(function(key) {
        	return Number(key) - 1
        })
      	.reduce(function(data, key) {
      		return data.children[key]
	      }, this.root)
      
      // 子孫にデータを伝搬させる
      this.walk(target, val)
    }
  }
})

Vue.component('item', {
  template: '#item-template',
  props: {
    model: Object
  },
  methods:{
    onChange: function(event) {
      store.$emit('change-at-parent', this.model.id, event.target.checked);
    }
  }
})


new Vue({
    el: '#app',
    data: {
        treeData: store.root.children
    }
})