简体   繁体   中英

How to pass a variable from twig to vueJS (symfony 2.8 and VueJS 2)

I have a symfony 2.8 application and I recently integrated VueJs 2 as my front-end framework, because it gives a lot of flexibility. My application is not single page and I use the symfony controllers to render views. All the views are wrapped in a base twig layout:

<!DOCTYPE html>
<html lang="{{ app.request.locale|split('_')[0] }}">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

</head>
<body>

<div id="app">
    {% block body %} {% endblock %}
</div>

<script src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script>
<script src="/js/fos_js_routes.js"></script>

<script type="text/javascript" src="{{ asset('build/vendor-bundle.js') }}"></script>
<script type="text/javascript" src="{{ asset('build/vue-bundle.js') }}"></script>

</body>
</html>

I load most of the JS with webpack, all my vue components and JS dependencies are compiled in vendor-bundle.js and vue-bundle.js . My VueJs instance looks like this:

import './components-dir/component.vue'
import './components-dir/component2.vue'

Vue.component('component', Component);
Vue.component('component2', Component2);

window.onload = function () {
new Vue({
        el: '#app',
        components: {}
    });
};

I want to pass some php variables from the controller to the vuejs componets, but I can't manage to make it work.

A very simple example of a controller looks like this:

    /**
     * @Route("/contract", name="contract")
     * @Method("GET")
     */
    public function indexAction()
    {
        $paymentMethods = PaymentMethod::getChoices();

        return $this->render('contracts/index.html.twig', [
            'paymentMethods'   => $serializer->normalize($paymentMethods, 'json'),
        ]);
    }

All the html, css and js are handled by vueJs. The twig view looks like this:

{% extends 'vue-base.html.twig' %}
{% block body %}
    <contracts :paymentMethods="{{paymentMethods | raw}}"></contracts>
{% endblock %}

The contracts.vue component looks like this:

<template>
    <div>
        <p>Hi from component</p>
    </div>
</template>

<script>
    export default {
        data() {
            return {}
        },
        props: ['paymentMethods'],
        mounted: function () {
            console.log(this.paymentMethods)
        }
    }
</script>
<style>
</style>

How can I pass the php variables as props to vueJs ?

In the example above, I don't get any errors, but the property is not passed to vuejs. The console log prints undefined . I want to be able to do this, because I don't want to have a SPA, but I also want to pass some variables from symfony to vue, because I won't have to make additional requests.

Instead of passing Twig variable as value of Vue attr:

<contracts :payment-methods="{{ twigVar}}"></contracts>

you can render whole using twig:

<contracts {{ ':payment-methods="' ~ twigVar ~ '"' }}></contracts>

Thanks to this you will avoid delimeters conflict between vue and twig.

Also as the value comes directly from twig, it probably wont change upon a time, as it is generated in backend - not in some vue-source - so you don't need to bind it, just pass it like:

<contracts payment-methods="{{ twigVar}}"></contracts>

您需要将以下内容添加到您的 .vue 文件props: ['paymentMethods']请参阅以下网址以获取完整文档https://v2.vuejs.org/v2/guide/components.html#Passing-Data-with -道具

The simplest way to pass variables from twig to Vue application is:

Twig:

<div id="app" data-foo="{{ foo }}" data-bar="{{ bar }}"></div>

JS:

import Vue from 'vue'

new Vue({
  el: '#app',
  data: {
    foo: '',
    bar: ''
  },
  template: '<div>foo = {{ foo }}</div><div>bar = {{ bar }}</div>',
  beforeMount: function() {
    this.foo = this.$el.attributes['data-foo'].value
    this.bar = this.$el.attributes['data-bar'].value
  }
})

If you would like to use a Vue component you can do it the following way:

Twig:

<div id="app" data-foo="{{ foo }}" data-bar="{{ bar }}"></div>

JS:

import Vue from 'vue'
import App from 'App'

new Vue({
  el: '#app',
  render(h) {
    return h(App, {
      props: {
        foo: this.$el.attributes['data-foo'].value,
        bar: this.$el.attributes['data-bar'].value,
      }
    })
  }
})

App.vue:

<template>
  <div>foo = {{ foo }}</div>
  <div>bar = {{ bar }}</div>
</template>

<script>
  export default {
    props: ['foo', 'bar'],
  }
</script>

Please note if you would like to pass arrays you should convert them to json format before:

Twig:

<div id="app" data-foo="{{ foo|json_encode }}"></div>

and then you should decode json:

JS:

this.foo = JSON.parse(this.$el.attributes['data-foo'].value)

Probably late to the party, but if anyone is having the same issue, the problem here was the casing.

CamelCased props like paymentMethods are converted to hyphen-case in html, and can be used like this:

<contracts :payment-methods="{{ paymentMethods | raw }}"></contracts>

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