symfony2admingenerator / AvocodeFormExtensionsBundle

(old-legacy) Symfony2 form extensions for Admingenerator project (also working standalone!)
Other
48 stars 31 forks source link

Problem with nested collection and javascript #74

Open montabou opened 10 years ago

montabou commented 10 years ago

I guess this problem is the same with several form type and I was wondering how it can be solved.

For example, when a collection is inside a collection, the javascript is not called when adding a new element that contains a collection. The new generated add and remove buttons are not working as the javascript initialization does not exist.

I was wondering if there is a generic solution to handle that problem or if it always has to be done using specific javascript code that initializes the new generated collection.

ioleo commented 10 years ago

@montabou There is a generic solution already working. Each form type that requires some JS initialization has a javascript_prototype block in Resources/views/Form/form_javascripts.html.twig.

Nested collections should be working. So, to trace the root of this problem, tell me if there are any JS errors when you add nested collections?

montabou commented 10 years ago

@loostro I don't think that it should work for now. Here is an illustration of the problem capture du 2013-11-04 15 12 17 The first add button works and generates the bloc form. However there is no javascript initialization call on the generated buttons and thus, the generated add button does not work.

The current javascript is

    jQuery(document).ready(function($) {
        var $field = $('#new_pagetranslation_pageTranslationBlocks');

            $field.bootstrapCollection({
        allow_add:        true,
        allow_delete:     true,
        sortable:         true,
        sortable_field:   "position",
        prototype_name:   "__name__",
        trans: {
            new_label:      "collection.new_label",
            confirm:        "Êtes-vous sûr de vouloir retirer cet élément ?",
            confirm_batch:  "Êtes-vous sûr de vouloir retirer tous ces éléments ?"
        },
        javascript: function(id) {
                          $field = $('#' + id + '_block');
                          $field = $('#' + id + '_position');
        }
    });
});

For me this is the normal behavior and I understand why it does not work. It misses the javascript initialization after pressing the first add button that would init add and remove buttons javascript.

I don't really need this, but I was wondering, so for me it's not really an issue as the behavior is what I expected. Do you really think that this should work ? Because I have no javascript error.

ioleo commented 10 years ago

@montabou this line should render the prototype block for your $field

in your code after $field = $('#' + id + '_block'); you should have initialization code

why it does not? that is the real question

    // it should look like this...
    $field = $('#' + id + '_block');
    $field.bootstrapCollection({
        // ... here options
    });
montabou commented 10 years ago

I see. I will not have a lot of time to dig into this problem but to complete the info:

The collection is not using the same EditType form as I got a loop problem at form generation. So I've created a new EditType that does not contain the children blocs

If I add a bloc the generated add/remove buttons do not work. If I save and edit it again the add/remove buttons work (as at refresh the javascript is updated) but if I add a new bloc the new generated add/remove buttons do not work (same problem as before).

Where it seems to be interesting is the javascript code:

    jQuery(document).ready(function($) {
        var $field = $('#edit_page_translations_fr_pageTranslationBlocks');

            $field.bootstrapCollection({
        allow_add:        true,
        allow_delete:     true,
        sortable:         true,
        sortable_field:   "position",
        prototype_name:   "__name__",
        trans: {
            new_label:      "collection.new_label",
            confirm:        "Êtes-vous sûr de vouloir retirer cet élément ?",
            confirm_batch:  "Êtes-vous sûr de vouloir retirer tous ces éléments ?"
        },
        javascript: function(id) {
                                                        $field = $('#' + id + '_block');

                                    $field = $('#' + id + '_position');

                                            }
    });
        });

As before the first javascript code correspond to the main working javascript add/remove buttons.

The javascript code for the edited bloc is however:

    jQuery(document).ready(function($) {
        var $field = $('#edit_page_translations_fr_pageTranslationBlocks_0_block_block');

            $field.bootstrapCollection({
        allow_add:        true,
        allow_delete:     true,
        sortable:         false,
        sortable_field:   "position",
        prototype_name:   "__name__",
        trans: {
            new_label:      "collection.new_label",
            confirm:        "Êtes-vous sûr de vouloir retirer cet élément ?",
            confirm_batch:  "Êtes-vous sûr de vouloir retirer tous ces éléments ?"
        },
        javascript: function(id) {
                                                        $field = $('#' + id + '_title');

                                    $field = $('#' + id + '_content');

                                    $field = $('#' + id + '_block');
                            $field.bootstrapCollection({
        allow_add:        false,
        allow_delete:     false,
        sortable:         false,
        sortable_field:   "position",
        prototype_name:   "__name__",
        trans: {
            new_label:      "collection.new_label",
            confirm:        "Êtes-vous sûr de vouloir retirer cet élément ?",
            confirm_batch:  "Êtes-vous sûr de vouloir retirer tous ces éléments ?"
        },
        javascript: function(id) {
                }
    });

                                            }
    });
        });

As we can see the form_javascript was generated even if it is not needed here as there is no children in new bloc.

Don't know if it's clear enough but I don't really understand why there is this behavior.

sescandell commented 10 years ago

@montabou

Could you please give us sample code to easily produce your case? (specific github project, or gist, or... something suffisant enough).

Thank you,

montabou commented 10 years ago

I did it quickly, a lot of stuff is useless and not working but it should be ok to illustrate the collection problem.

git clone https://github.com/montabou/AvocodeTest.git
composer.phar update
mkdir app/data # for the sqlite database
app/console doctrine:schema:update --force
setfacl -R -m u:www-data:rwx -m u:`whoami`:rwx app/data/
setfacl -R -m u:www-data:rwx -m u:`whoami`:rwx app/cache/
setfacl -R -m u:www-data:rwx -m u:`whoami`:rwx app/logs/
setfacl -dR -m u:www-data:rwx -m u:`whoami`:rwx app/data/
setfacl -dR -m u:www-data:rwx -m u:`whoami`:rwx app/cache/
setfacl -dR -m u:www-data:rwx -m u:`whoami`:rwx app/logs/
app/console assets:install

If you go to

app_dev.php/admin/acme_test_bundle/Page/new

You can not add a block children because of lack of javascript. If you create a new page with a block and save it. When you edit this block you can add children block.

Hope this help

sescandell commented 10 years ago

@montabou

Thanks a lot, it will be perfect to test and debug.

Thank you,

montabou commented 10 years ago

I've found the problem and I have a solution but... I don't know if that's correct.

For me the problem is located here

As {% block form_afe_javascript_prototype %}{% endblock form_afe_javascript_prototype %} is empty, when it's called from {{ afe_form_javascript(..., true) }} it does nothing.

I've changed by this:

{% block form_afe_javascript %}
{% spaceless %}
    {% for child in form %}
        {{ afe_form_javascript(child) }}
    {% endfor %}
{% endspaceless %}
{% endblock form_afe_javascript %}

{% block form_afe_javascript_prototype %}
{% spaceless %}
    {% for child in form %}
        {{ afe_form_javascript(child, true) }}
    {% endfor %}
{% endspaceless %}
{% endblock form_afe_javascript_prototype %}

Then the child id was not correct as it depends on its parent id. In AvocodeTest for example, the id was #edit_page_translations_fr_pageTranslationBlocks_0_block instead of #edit_page_translations_fr_pageTranslationBlocks_0_block_children

so I've added the parent name:

{% block form_afe_javascript_prototype %}
{% spaceless %}
    {% for child in form %}
        $field = $('#' + id + '_{{ child.parent.vars.name }}_{{ child.vars.name }}');
        {{ afe_form_javascript(child, true) }}
    {% endfor %}
{% endspaceless %}s
{% endblock form_afe_javascript_prototype %}

@loostro Do you think it's ok for a PR ? I was wondering why the form_afe_javascript_prototype block was originally inside form_afe_javascript block ?

montabou commented 10 years ago

Arf, the trick I did using child.parent.vars.name is not necessary when it's more complicated with more nested collection and stuff. I will do a PR with an other solution that works for me when there is a singleupload file within a translation entity collection.

ioleo commented 10 years ago

@montabou @sescandell i think the error may be becouse the blocks were renamed... if I remember correct, the form:

afe_myForm should have corresponding afe_myForm_widget (for view template) and afe_myForm_javascript (for js template)

The afe_javascript_prototype block works the same way as form_widget_prototype block in standard symfony2 forms..

But I see it has been renamed to form_afe_javascript_prototype and maybe that causes the problem (as it does not anymore "automagically discover" that it should put the prototype for the javascript block)

Try going back to "before prefix" tag (before the block names changes) and see if that helps?

If it works, then we must make a PR to fix the names of the blocks.

montabou commented 10 years ago

@loostro I'm not sure if I well understand your explanation but the problem occured before the prefix afe as I've got that problem more than 4 months before (before the afe prefix).

I've tested though using this

And it does not work

But if I modify the form_javascript.html.twig as the same as my PR (form_javascript and form_javascript_prototype blocks), it works again.

ioleo commented 10 years ago

@montabou which version of symfony you use?

montabou commented 10 years ago

as in https://github.com/montabou/AvocodeTest v2.3.* last update v2.3.11