0

I am trying to get a recursive directive working in angular. After quite a bit of time on stackoverflow and digging through the angular documentation I have got most of it working. I'm having a hard time getting the actions working though. The object is getting updated as I would expect, but the directive doesn't seem to be redrawn accordingly.

Here is the directive:

.directive('formgenerator', ['$compile', function ($compile) {
        return {
            restrict: 'E',
            terminal: true,
            scope: { val: '=', index: '=' },
            replace: true,
            link: function (scope, element, attrs) {
                var template = '<div data-ng-if="val">';
                template += !scope.val.type ? ''
                        : scope.val.type === 'text' ? '<label>{{val.label}}</label><input type="text" data-ng-model="val.value"></input><button ng-click="deleteMe(index)">delete</button>'
                            : scope.val.type === 'select' ? '<label>{{val.label}}</label><select data-ng-model="val.value" data-ng-options="v.name for v in val.values track by v.id"></select><button ng-click="deleteMe(index)">delete</button>'
                                : scope.val.type === 'multiselect' ? '<label>{{val.label}}</label><select data-ng-model="val.value" multiple="multiple" data-ng-options="v.name for v in val.values track by v.id"></select><button ng-click="deleteMe(index)">delete</button>'
                                    : '';
                template += '</div>';
                if (angular.isArray(scope.val.inputs)) {
                    template += '<ul class="indent"><li ng-repeat="input in val.inputs track by $index"><formgenerator val="input" index="$index"></formgenerator></li></ul>';
                }

                scope.deleteMe = function (index) {
                    scope.$parent.val.inputs.splice(index, 1);
                    //var inpts = scope.$parent.val.inputs;
                    //inpts.splice(index, 1);
                    //scope.$parent.val.inputs = inpts;

                    //scope.$parent.$parent.val.inputs.splice(index, 1);
                    //scope.$parent.$parent.$parent.val.inputs[scope.$parent.this.index].inputs.splice(scope.$parent.this.index, 1);
                };

                var newElement = angular.element(template);
                $compile(newElement)(scope);
                element.replaceWith(newElement);
            }
        };
    }]);

Here is the object the controller is passing into the directive:

form = {
            inputs:
            [
                {
                    type: 'text',
                    value: 'textValue',
                    label: 'Text value',
                    defaultValue: 'defaultTextValue'
                },
                {
                    inputs:
                    [
                        {
                            type: 'text',
                            value: 'textValue1',
                            label: 'Text value1',
                            defaultValue: 'defaultTextValue1'
                        },
                        {
                            type: 'select',
                            value: 'textValue2',
                            values: [{ name: '1st', id: 1 }, { name: '2nd', id: 2 }],
                            label: 'Text value2',
                            defaultValue: 'defaultTextValue2'
                        },
                        {
                            type: 'multiselect',
                            value: 'textValue3',
                            values: [{ name: '1st', id: 1 }, { name: '2nd', id: 2 }],
                            label: 'Text value3',
                            defaultValue: 'defaultTextValue3'
                        }
                    ]
                }
            ]
        };

Here is the jsFiddle: http://jsfiddle.net/5YCe7/1/

Basically, if I hit the delete button next to Text value2, I would expect the single select to 'disappear' and the multiselect to 'move up'. What seems to be happening though is that the values of the multiselect move in place of the values for the select.

Any help on this would be greatly appreciated.

peinearydevelopment
  • 11,042
  • 5
  • 48
  • 76
  • Can I ask you the reason to write a recursive directive rather than using ng-repeat with the 'template' attribute to achieve this? – Sid Jul 17 '14 at 20:11
  • Could you give an example of what you are talking about? Basically, I would like to use this to create a form for non predetermined object. I don't know the level of nesting for it ahead of time. Might be like above or i could be a Person that has multiple Addresses each of which can have multiple Phone numbers associated with it. Could you provide an example of what you are talking about if you think it would for my scenario? – peinearydevelopment Jul 17 '14 at 20:17

1 Answers1

0

There are a few errors here:

  1. When you press deleteMe, you need to again compile and replace the element with the new element. link won't automatically be called again.
  2. I don't think your index is being assigned correctly

I would recommend looking at a few links before making recursive directives:

Is it possible to make a Tree View with Angular? Recursion in Angular directives

Community
  • 1
  • 1
Sid
  • 7,511
  • 2
  • 28
  • 41
  • I've tried stepping through this in firefox and the index seems to be coming in correctly as far as I can tell. What should I be calling compile on again, I'm not creating any new elements? Could you update the jsFiddle? I would also like to add an 'addAnother' method as well so understanding what you are saying would help alot. Thanks. – peinearydevelopment Jul 17 '14 at 20:41
  • You would need to call the compile and replace (as you are doing initially in the link) in your delete and add as well. Basically whenever you are making a change to the element. – Sid Jul 17 '14 at 20:44
  • I understand what you are said, but before, in the link I'm creating a newElement from my template. On the delete me, I have no template, what is my newElement supposed to be(and the old element also --> seems like scope.$parent.$parent.$parent is the object, but not sure which property would contain the element). – peinearydevelopment Jul 17 '14 at 20:50
  • I am not sure how to access the original (parent) element from the child as you need to remove the child and re-render the parent. You may want to study the links I posted. – Sid Jul 17 '14 at 21:12
  • Thanks, I'll look at the first link. The second link is where I got most of the initial recursion from, but I don't see in there anything like what you are talking about. In fact, there is a deleteMe method on one of those jsFiddles that doesn't really seem to work at all(it has an if statement that always seems to be false and then sets the val = {} which has a visual effect of being remove, but I don't think it does what you are talking about). – peinearydevelopment Jul 17 '14 at 21:18