Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

editable with ngrepeat: automatically editing the latest added item

I need to add new items to a collection, that gets rendered with ngrepeat and using xeditable make it automatically editable.

BTW, I'm using the "manual trigger" method for xeditable.

Here it is the HTML

<h4>Angular-xeditable demo</h4>
<div ng-app="app" ng-controller="Ctrl" style="margin: 50px">
<div class="btn btn-default" ng-click="addNew()">+</div>
<ul>
  <li ng-repeat="item in array | orderBy:'-value'">
    <a href="#" e-form="itemForm" editable-text="item.field">{{ item.field }}</a>
    <i ng-show="!itemForm.$visible" ng-click="itemForm.$show()">edit</i>
  </li>
</ul>
</div>

and here the controller:

var app = angular.module("app", ["xeditable"]);

app.run(function(editableOptions) {
  editableOptions.theme = 'bs3';
});

app.controller('Ctrl', function($scope, $filter) {

  $scope.array = [
    {value: 1, field: 'status1'},
    {value: 2, field: 'status2'},
    {value: 3, field: 'status3'},
    {value: 4, field: 'status4'}
  ]; 

  $scope.addNew = function(){
    $scope.array.push({value:$scope.array.length+1, field: 'enter text here'});
    //MAKE IT EDITABLE????????
  }
});

Take a look to the issue in this fiddle: http://jsfiddle.net/dpamio/hD5Kh/1/

like image 809
Diego Pamio Avatar asked Oct 02 '22 10:10

Diego Pamio


2 Answers

Here is a updated fiddle that works. Because of how the directive was written, and how ng-repeat works, it required an extremely hacky solution...

app.controller('Ctrl', function($scope, $filter, $timeout) {

  $scope.itemForms = {};

  $scope.addNew = function(){
    $scope.array.push({value:$scope.array.length+1, field: 'enter text here'});

     // Use timeout to force evaluation after the element has rendered
     // ensuring that our assignment expression has run
     $timeout(function() {
         $scope.itemForms[0].$show(); // last index since we sort descending, so the 0 index is always the newest
     })
  }

Background on how ng-repeat works: ng-repeat will create a new child scope for each element that is repeated. The directive assigns a variable on that scope using the string passed into e-form for its name (in this case itemForm). If it was smarter, it'd allow for expression evaluation for assignment. (Then we could assign it to the parent scope, and access it in the controller, but that's a different matter).

Since we don't have any way to access this child scope outside of the directive, we do something very bad. We use the mustache expression in a span of display none to assign the itemForm variable to the parent scope so that we can use it later. Then inside our controller we use the look up value to call the itemForm.$show() method that we expect.

Abstracting that bit of nastyness into an angular directive, we could write the following:

.directive('assignFromChild', function($parse) {
    return {
        restrict: 'A',
        link: function(scope, el, attrs) {
            scope.$watch(function() { return $parse(attrs.assignFromChild)(scope); }, function(val) {
                $parse('$parent.' + attrs.toParent).assign(scope, val);
            })
        }
    }; 
});

Allowing our HTML to go back down to:

<ul>   
  <li ng-repeat="item in array | orderBy:'-value'" assign-from-child="itemForm" to-parent="itemForms[{{$index}}]">
    <a href="#" e-form="itemForm" editable-text="item.field">{{ item.field }}</a>
    <i ng-show="!itemForm.$visible" ng-click="itemForm.$show()">edit</i>
  </li>
</ul>

Here is a fiddle with my final solution

like image 131
Ryan Avatar answered Oct 22 '22 14:10

Ryan


I found a very simple solution using ng-init="itemForm.$show()", that will activate the xeditable form when the new item is inserted.

Here's the updated jsFiddle answering the question: http://jsfiddle.net/hD5Kh/15/

like image 38
cnlevy Avatar answered Oct 22 '22 12:10

cnlevy