Angular.js inline-editing (append compiled html to directive?)

2,328 views
Skip to first unread message

fxck

unread,
Apr 3, 2013, 8:38:47 AM4/3/13
to ang...@googlegroups.com
I'm trying to find the best approach of inline-editing with angularjs. In my case it's kind of a data-grid with an "edit" button. So it's inside ng-repeat.

What I've seen people do is have both actual data and editing inputs in the same row, with editing inputs being hidden and shown on click of the edit button.

But it doesn't seem right. It's a lot of useless DOM in my opinion.

So I thought I would be better to do something like this. You click on the edit button, which is gonna have a directive, which would 1) hide the `<td>` with data 2) find buttons' parent, which should be the `<tr>`, and inject a template with <td><input></td> into it 3) on save remove those editing `<td>`s and show the data `<td>`s again.

So I started with making the directive, inside I had `element.click()` function, which

    // found the parent
    var parent = element.closest('tr');
    // found all the data tds
    var tds = parent.find('td');
    // hidden them   
    tds.hide();

Now here's the problem, next I thought about doing something like this

    // append input with editing tds into parent
    parent.append('<td><input type="text" ng-model="entry.name" /> {{entry.name}} </td>');

But then it wouldn't bind or even parse the {{}} would it? What method would I have to use instead of jquery's append?

Docu on directives says this

template element - The element where the directive has been declared.
It is safe to do template transformation on the element and child
elements only.

So I can't use template transformation on the element.parent()

Would it help if I made the directive on the `<tr>` and even if I did, I would then transform my whole `<tr>`, which means I'd lost the original template and I'd have to have another directive or something that would transform it back to the original state.. wouldn't I?

fxck

unread,
Apr 3, 2013, 8:50:28 AM4/3/13
to ang...@googlegroups.com
What I managed to do so far was do this

app.directive('clEditRow', ['$compile', function(compile) {
    return {
        link: function(scope, element, attrs) {
            element.find('.editbtn').bind('click', function() {

                var template = angular.element(

                    '<td><input type="text" ng-model="entry.name" /> {{ entry.name }}</td>'
                );
                compile(template.contents())(scope);

                element.prepend(template);

            });
        }
       

    }

}]);


which somehow works and updates the original entry.name, but {{ entry.name }} in the directive element is not parsed until I make some changes(start typing)..

fxck

unread,
Apr 3, 2013, 8:51:59 AM4/3/13
to ang...@googlegroups.com
...and the input is empty, instead of being prefilled with original entry.data

fxck

unread,
Apr 3, 2013, 9:03:30 AM4/3/13
to ang...@googlegroups.com
scope.$apply(); after compile did the trick... but I'm still not sure this is the right way of doing it.

Dennis Loewel

unread,
Apr 3, 2013, 12:32:42 PM4/3/13
to ang...@googlegroups.com
I'm not sure if it fits your problem. Instead of replacing whole tds...  I would try something like this:

<tr ng-repeat="entry in list" ng-init="editing=false"> 
  <td>
   <span ng-hide="editing">{{entry.field1}}</span>
   <input type="text" ng-model="entry.field1"/>
  </td>
  <td>
   <span ng-hide="editing">{{entry.field2}}</span>
   <input type="text" ng-model="entry.field2"/> 
  </td>
  <td>
   <button ng-click="editing=true" ng-hide="editing">Edit</button>
   <button ng-click="editing=false; save(entry)" ng-show="editing">Save</button> 
  </td>
</tr>

My idea here is to show and hide the value or input-field while editing or not editing. It would be much better with ui-if from AngularUI, cause it removes the whole element instead of just hiding it. For this way you don't need any directive. The power of how angular extends html is very useful... but, maybe it's not your way. :)

Dennis Loewel

unread,
Apr 3, 2013, 12:33:32 PM4/3/13
to ang...@googlegroups.com
I forgot the ng-show="editing" on both input fields...

fxck

unread,
Apr 3, 2013, 12:46:46 PM4/3/13
to ang...@googlegroups.com
That's what I said I didn't really want to do. Imagine I have 80 row in the table and each with 10 cols, most of the cols will have some kind of plugin attached to them(select2, datepicker, timepicker)... That's a lot of unnecessary shizzle hidden away, isn't it?

What I ended up with is essentially this http://run.plnkr.co/C9v0XPeI99Hlhi9j/ it somehow works, but I have no idea how is it performance wise..

Dennis Loewel

unread,
Apr 4, 2013, 5:20:14 AM4/4/13
to ang...@googlegroups.com
Hehe, ya of course. Therefor use ui-if, as I mentioned. Your way seems to be faster on the first rendering, but isn't that flexible if you want to change something, because the row affects the directive and vice verca. Using select2, datepicker, timepicker doesn't affect this situation, because these are already directives. 

My intention was to prevent hiding td's, temporary insert new ones and abstracting this to a directive which only work with that situation. So, if you had a real benefit like the first rendering, using a directive is a good idea - especially if you want to display 80 rows! If you need this for few rows only, I dont think you need a special directive. :) (My opinion)

Btw, I cannot view your plnkr. :(

fxck

unread,
Apr 4, 2013, 7:10:17 AM4/4/13
to ang...@googlegroups.com
plnkr keep deleting it for some reason.. and I can't seem to be able to even access it right now..
Reply all
Reply to author
Forward
0 new messages