brookinsconsulting/bcknockoutjsbundle
Installation:
composer require brookinsconsulting/bcknockoutjsbundle:dev-master
Add to AppKernel.php:
new BrookinsConsulting\BcKnockoutJSBundle\BcKnockoutJSBundle(),
Import config in config.yml:
imports:
- { resource: "@BcKnockoutJSBundle/Resources/config/config.yml" }
Basic Usage:
<script src="{{ asset('bundles/bcknockoutjs/js/knockout-3.4.1.js') }}"></script>
{{ knockout(form.vars.knockout)|raw }}
{{ form_widget(form) }}
First Use Case:
Define a CollectionType field with knockout type in your form builder:
$builder->add('items', 'knockout', [
'type' => new OrderItemType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
]);
Dynamic Collections:
Use allow_add/allow_delete to enable CRUD operations for collection items:
$builder->add('tags', 'knockout', [
'type' => new TagType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true, // Renders a hidden template for new items
]);
Nested Forms:
Combine with Symfony’s CollectionType for multi-level Knockout integration:
$builder->add('categories', 'collection', [
'type' => new CategoryType(),
'allow_add' => true,
'prototype' => true,
'by_reference' => false,
'knockout' => true, // Enable Knockout for nested collections
]);
Custom Templates: Override the prototype template in Twig:
{% block knockout_prototype_items %}
<div class="new-item">
{{ form_row(form.prototype) }}
<button type="button" class="remove-item">Remove</button>
</div>
{% endblock %}
Data Binding: Bind form data to a Knockout observable:
{{ knockout(form.vars.knockout, {
'data-bind': 'foreach: items, with: $data'
})|raw }}
knockout-3.4.1.js is accessible via asset().knockout.html.twig for consistent styling.ko.validation for client-side feedback.FormHandler for seamless server-side updates.Deprecation Warning: The bundle is deprecated (Symfony 2/3 only). Avoid in new projects; consider alternatives like:
JMS DI Extra:
The jms_di_extra config is unnecessary if all_bundles: true is set elsewhere (performance risk).
Prototype Template:
Forgetting prototype: true breaks "Add Item" functionality. Ensure the template block (knockout_prototype_*) exists.
Knockout Version Lock: The bundle ships with Knockout 3.4.1. Conflicts may arise if other bundles include newer versions.
Form Events:
Knockout’s add/remove events may not trigger Symfony’s PRE_SUBMIT/POST_SUBMIT lifecycle. Handle manually:
ko.applyBindingsToNode(document.getElementById('your-form'), {
createViewModel: function() {
return { items: formData.items };
}
});
Check form.vars.knockout:
Inspect the rendered Twig variable to verify Knockout data is passed correctly.
{{ dump(form.vars.knockout) }}
Console Errors: Knockout errors often appear in the browser console. Look for:
Cannot read property 'applyBindings' of undefined (missing ko global).Template not found (incorrect prototype template block name).Symfony Profiler: Use the Form panel to debug collection data binding.
Custom Types:
Extend BrookinsConsulting\BcKnockoutJSBundle\Form\Type\KnockoutType for specialized behavior.
Template Overrides:
Override BcKnockoutJSBundle:Form:knockout.html.twig for global changes.
JavaScript Extensions: Add custom Knockout bindings in a separate JS file:
// assets/js/knockout-extensions.js
ko.bindingHandlers.customBinding = { /* ... */ };
Include it after the bundle’s Knockout script.
Server-Side Logic:
Use Symfony’s PRE_SET_DATA to pre-populate Knockout observables:
$form->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$data = $event->getData();
$event->getForm()->vars['knockout']['initialData'] = $data->toArray();
});
How can I help you explore Laravel packages today?