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 ponents and JS dependencies are piled in vendor-bundle.js
and vue-bundle.js
. My VueJs instance looks like this:
import './ponents-dir/ponent.vue'
import './ponents-dir/ponent2.vue'
Vueponent('ponent', Component);
Vueponent('ponent2', Component2);
window.onload = function () {
new Vue({
el: '#app',
ponents: {}
});
};
I want to pass some php variables from the controller to the vuejs ponets, 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
ponent looks like this:
<template>
<div>
<p>Hi from ponent</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.
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 ponents and JS dependencies are piled in vendor-bundle.js
and vue-bundle.js
. My VueJs instance looks like this:
import './ponents-dir/ponent.vue'
import './ponents-dir/ponent2.vue'
Vue.ponent('ponent', Component);
Vue.ponent('ponent2', Component2);
window.onload = function () {
new Vue({
el: '#app',
ponents: {}
});
};
I want to pass some php variables from the controller to the vuejs ponets, 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
ponent looks like this:
<template>
<div>
<p>Hi from ponent</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.
- Did you find a solution ? – Benjamin Seche Commented Jun 25, 2018 at 12:38
4 Answers
Reset to default 2Instead 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 es 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>
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 ponent 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)
you need to add the following to your .vue file props: ['paymentMethods']
please refer to the following url for plete documentation https://v2.vuejs/v2/guide/ponents.html#Passing-Data-with-Props
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>