Reputation: 131
I have Symfony Form which defined as below (minus non-pertinent fields for brevity):
<?php
namespace AppBundle\Form;
use AppBundle\Entity\Category;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class CategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('label', TextType::class, [
'label' => 'label.display_name',
'attr' => [
'placeholder' => 'placeholder.category_name',
'class' => 'label',
'@input' => 'vUpdateSlug'
]
])
->add('slug', TextType::class, [
'label' => 'label.slug',
'attr' => [
'class' => 'slug',
'@input' => 'vUpdateSlug',
':value' => 'slug'
]
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Category::class,
'category_id' => null
]);
}
}
I am attaching Vue.js directives to both input
fields. The idea is that when someone types in the label
field, the slug
field is automatically updated with the label
input
value with some minor changes (replacing spaces with hyphens). I still want the user to be able to alter the slug if they wish, but not have the label update.
The v-on:input/@input
directive behaviour works, however, I'm just starting with Vue.js and my implementation feels a little clunky (repetitive) - see below:
new Vue({
delimiters: ['[[', ']]'],
el: '#category-form',
data: {
slug: this.slug = $('[name="category[slug]"]').val()
},
ready: function () {
this.slug = $('[name="category[slug]"]').val();
},
methods: {
vUpdateSlug: function (event) {
var str = event.target.value.replace(/[^a-zA-Z0-9 -]/g, '').replace(/\s+/g, '-').toLowerCase();
return this.slug = str;
}
}
});
Is there a better solution to my problem?
Upvotes: 2
Views: 1107
Reputation: 131
After more researching and tinkering, I came up with the following which produces the desired result:
CategoryType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('label', TextType::class, [
'label' => 'label.display_name',
'attr' => [
'placeholder' => 'placeholder.category_name',
'class' => 'label',
'v-model' => 'label'
]
])
->add('slug', TextType::class, [
'label' => 'label.slug',
'attr' => [
'class' => 'slug',
'@input' => 'setSlug',
':value' => 'slug'
]
]);
}
Vue Script
new Vue({
delimiters: ['[[', ']]'],
el: '#form-wrapper',
data: {
label: $('[name="category[label]"]').val(),
slug: $('[name="category[slug]"]').val()
},
watch: {
label: function(newLabel) {
this.slug = this.compileSlug(newLabel)
}
},
methods: {
compileSlug: function(input) {
return input.replace(/[^a-zA-Z0-9 -]/g, '')
.replace(/\s+/g, '-')
.toLowerCase();
},
setSlug: function (input) {
this.slug = this.compileSlug(input.target.value)
}
}
});
Upvotes: 1