简体   繁体   中英

Laravel 5.3, Vue.js 2+ can't get List Rendering (v-for) working

public/js/symp.js (initial post)

new Vue({
  el :'#symp',
  data :{
    tease: 'test',
    items: [
      { message: 'Foo', subject: 'A' },
      { message: 'Bar', subject: 'B' }
    ]
  }
});

resources/views/dash.blade.php (initial post)

<html>
<body>
@extends('layouts.app')  [ this includes symp.js and calls @yeild('content') ]

@section('content')
<div id="symp">
  <div>
  <span>subject</span>
  <span>message</span>
  </div>
  tease: <span>@{{ tease }}</span>
  <div v-for="item in items">
  sub: <span>@{{ item.subject }}</span>
  msg: <span>@{{ item.message }}</span>
  </div>
</div>
@endsection

I know Laravel fights with {{ }} and so need to prepend @, but my understanding is demo snippet code above should present tease: test then two rows
sub: A msg: Foo
sub: B msg: Bar
... alas, I see the tease: subject message, no tease value, and no rows present at all.

What's hilarious, I have a folder as part of a project I'm building that has working version of http://www.hc-kr.com/2016/11/laravel-5-vuejs-crud-with-notification-pagination-laravel.html in place, however that folder forces Vue.js 1.x, so it seems this is unique issue with Laravel 5.3's vue.js 2.x?


[ updated per @PanJunjie潘俊杰 suggestion :-) ]

resources/views/dash.blade.php

@extends('layouts.app')

@section('content')
<div id="symp">
</div>
@endsection

resources/views/layout/app.blade.php

<html>
<script src="/js/app.js"></script>
<body>

...

<template id="symp-temp">
tease: <span>@{{ tease }}</span>
<div v-for="item in items">
  sub: <span>@{{ item.subject }}</span>
  msg: <span>@{{ item.message }}</span>
</div>
</template>

</body>

<script src="/js/symp.js"></script>
</html>

public/js/symp.js

new Vue({
  el :'#symp',
  name: 'symp',  /*  unnecessary?  */
  template: '#symp-temp',  /* this helps a bit :-)  */
  data :{
    tease: 'well',
    items: [
      { message: 'Foo', subject: 'A' },
      { message: 'Bar', subject: 'B' }
    ]
  }
});

Some progress. The tease value now shows, but the item rows still don't show. JavaScript console reports this ...

[Vue warn]: Component template should contain exactly one root element:

tease: <span>{{ tease }}</span>
<div v-for="item in items">
  sub: <span>{{ item.subject }}</span>
  msg: <span>{{ item.message }}</span>
</div> 

The mount point denoted by el will have what's inside it overwritten by vue's rendered html, you shouldn't put your template inside it. Ways to correct it (first one may be best as you may want to keep your templates in your blade files):

  • Move your template out of <div id="symp"> and tell vue to use it as template like: <template id="symp-temp">...<template> and add a template: '#symp-temp' option to your new Vue . (custom markups are valid in html5 standard)

  • Move templates to .js files and wrap them in ES6's ` s which allows line breaks in quotes. Put the backquoted string in template option.

  • Use .vue single file components .

This worked fine in Vue 1.x but in vue 2 you need wrap your template around a div tag on :

resources/views/layout/app.blade.php

<template id="symp-temp">
    <div>
        tease: <span>@{{ tease }}</span>
        <div v-for="item in items">
            sub: <span>@{{ item.subject }}</span>
            msg: <span>@{{ item.message }}</span>
        </div>
    </div>
</template>

You can checkout the issue on github https://github.com/vuejs/vue-loader/issues/384

Egad, this was an obtuse wild goose chase.

1) Be careful to put extra div's around elements to isolate them. Notice tease now has dedicated div surrounding it, and the item... v-for has a different dedicated div surrounding it. Without that Vue 2+ gets confused and won't play ball.

<template id="symp-temp">
<div>
<div>tease: <span>@{{ tease }}</span></div>
<div v-for="item in items">
  sub: <span>@{{ item.subject }}</span>
  msg: <span>@{{ item.message }}</span>
</div>
</div>
</template>

2) For some reason this.$set(...) I guess is deprecated (or needs extra scope that I'm not aware of). Using Vue.set with full parameters seems to work though in Vue 2+ world.

Vue.set(this, 'items', response.data.data.data);

I may find more gremlins, but it looks like I'm unstuck for now :-)


For more context, here's more of the code I was trying to enable. I'm doing quite a bit of custom layout experimentation so avoiding components until more of our data schema settles down.

new Vue({
  el :'#symp',
  name: 'symp',
  template: '#symp-temp',
  data :{
    tease: 'well',
    items: [
      { message: 'Foo', subject: 'A' },
      { message: 'Bar2', subject: 'B' }
    ],
    pagination: {
      total: 0,
      per_page: 2,
      from: 1,
      to: 0,
      current_page: 1
    }
  },
  mounted: function() {
    this.getVueItems(this.pagination.current_page);
  },
  methods: { 
    getVueItems: function(page) {
      /*  URL /make is a Laravel resource that pulls rows from a database,
      /*  returns them in json list, which the Vue.set transfers to the template :-)  */
      this.$http.get('/make?page='+page).then((response) => {
        Vue.set(this, 'items', response.data.data.data);
      });
    } 
  }
}); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM