4

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.

1
  • Did you find a solution ? Commented Jun 25, 2018 at 12:38

4 Answers 4

2

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>
Sign up to request clarification or add additional context in comments.

Comments

1

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)

Comments

1

you need to add the following to your .vue file props: ['paymentMethods'] please refer to the following url for complete documentation https://v2.vuejs.org/v2/guide/components.html#Passing-Data-with-Props

5 Comments

Sorry I've forgotten to write that in my .vue file I have the props property already defined. I've updated my question.
do you have the vue DevTools installed? if so go to the root and check what paymentMethods shows. @StefanGramadnikov
whoops remove the : from :paymentMethods it shoud be just paymentMethods
Tried it both ways, the difference is that with : the property is dynamic, but in my case it doesn't matter.
well when you use the : itll think its a vue variable.
0

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>

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.