Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: better support for inline formsets #78

Open
AgDude opened this issue Jul 4, 2014 · 10 comments
Open

Feature Request: better support for inline formsets #78

AgDude opened this issue Jul 4, 2014 · 10 comments

Comments

@AgDude
Copy link
Contributor

AgDude commented Jul 4, 2014

I am currently working on implementing inline formsets locally. Has anyone else used django-angular with inline formsets.

What I have in mind is putting the inline forms into an array, so I can use ng-repeat as I add or remove forms.

so the scope_prefix object would look something like this:

{ field1 : ,
field2: ,
child_model: [
  {childfield1, 
  childfield2},
  {childfield1, 
  childfield2},
...
]}

The other issue to address is putting ng-model on the django management forms, so those can be manipulated as forms are added/removed.

I am opening this issue as a place to keep track of how to implement this, if my workload permits I will update the demo and docs when I get it working. Any feedback or ideas are greatly appreciated.

@AgDude
Copy link
Contributor Author

AgDude commented Jul 4, 2014

I have added ng-model to the management form by modifying it in the as_ul method on the formset class. This feels like a bit of hack, but since the management form is dynamically generated in a property method it is not easy to override.

AngularFormSet(forms.models.BaseInlineFormSet):

    def as_ul(self):
        forms = ' '.join([form.as_ul() for form in self])
        management_form = self.management_form
        for name, field in management_form.fields.iteritems():
            field.widget.attrs['ng-model'] = '%s.%s' % (self.prefix, name)
        return mark_safe('\n'.join([six.text_type(management_form), forms]))

@AgDude
Copy link
Contributor Author

AgDude commented Jul 4, 2014

Pushing an unknown number of forms into the array is going to be problematic. Clearly we will need to initialize the array in the controller, but it can't be empty. When we put an ng-model property like this:

ng-model = "form_data.children[0].childfield1"

form_data.children[0] is undefined, so we can't set childfield1. What we really need is an empty object. Basically we need to subclass Array so that get returns an empty object if it doesn't exist. There is an excellent discussion of subclassing Array at the link below. It is doable, but not a trivial task.
http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/

For my application I am going to set the max number of forms at 20, and initialize the array like so:

Array.apply(null, new Array(20)).map(function(){return {}})

This is going to work just fine for my use case, but doesn't seem robust enough to put into django-angular.

Edit:
on further consideration there are some real drawback to this approach. First, children.length will be meaningless, since it will always be 20. ng-repeat is going to get a bunch of empty objects.

I think I'll put something in the controller to remove the empty objects after the page loads. Obviously far from ideal.

@jrief
Copy link
Owner

jrief commented Jul 4, 2014

The Zen of this project is to do stuff such as form rendering the “Djagno”-way. First, when I started, I was proud to not have any Javascript code at all. Well, these times are gone, but JS still takes a small footprint of the project. I therefore prefer to use Django templates for rendering, etc.
This does not mean to abandon Javascript completely, but if you can choose between doing it on the server or doing it on the client, I prefer the server.
I know, this is in stark contrast to the REST philosophy, but that's my intention.

Since I'am short of time, I'll come back to this in a month or so.
Jacob

@AgDude
Copy link
Contributor Author

AgDude commented Jul 4, 2014

I think that Zen is one of the things I like about this project, myself having been acquainted with Django much longer than Angular. I'll keep that in mind as I am working on my implementation.

One of my requirements is to be able to add/remove inline forms on the client, so some javascript is going to be needed.

@vaibhav-jain
Copy link

I have a InlineFormset that I want to validate . Can this plugin do that.???

@jrief
Copy link
Owner

jrief commented Jan 28, 2015

AngularJS doesn't know about the concept of formsets. In AngularJS the form validation is done using the $scope.formname.fieldname. If you manage to get the same names for the fields, form validation should also work.
Let me know fi you can figure it out yourself.
As a hint: the unit tests run nested forms, so please check there too.

@vaibhav-jain
Copy link

Thanks I will try. Right now I am trying to integrate bootstrap formvalidation plugin. But due to different names it is now working.

@craftycorvid
Copy link
Contributor

craftycorvid commented Aug 9, 2016

I solved the Management Form issue in what I believe is a more elegant way, using a template tag to render it.

@register.simple_tag
def djng_formset_management_form(formset):
    management_form = formset.management_form
    scope_prefix = formset.form.scope_prefix
    for name, field in management_form.fields.iteritems():
        field.widget.attrs['ng-model'] = ("%s['%s-%s']" % (scope_prefix, formset.prefix, name)) if scope_prefix else \
            '%s-%s' % (formset.prefix, name)
    return management_form

@craftycorvid
Copy link
Contributor

There's one final issue that I haven't seen solved in any of these tickets regarding formsets. add_prefix in NgFormBaseMixin changes dots to dashes, which works fine for regular forms because that same add_prefix is called during validation. This is not true during formset validation, however.

_construct_form in django.forms.models.BaseModelFormSet has the dash hard-coded. Is this a bug in django?

I'm going to work around it for now, but this would have to be addressed if this will someday be supported in django-angular.

@adrienbrunet
Copy link
Collaborator

@Ivan0xFF Would you like to contribute and add your work to django-angular? Better support and documentation is one of the last thing lacking for this module. (Beside Angular2 which is another subject)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants