2014-10-08 7 views
0

В моей модели у меня есть поле, в котором мне нужно несколько элементов управления для привязки. Одним из этих элементов управления является текстовое поле. Текстовое поле не должно напрямую редактировать поле, но вместо этого оно должно позволить пользователю вводить, а затем либо фиксировать изменения, либо отменять. Если какая-либо другая операция выполняется, она должна перезаписать любые изменения в текстовом поле. Одним из ограничений является наличие других компонентов пользовательского интерфейса, которые изменяют значение и не имеют доступа к локальной области.Как реализовать разрешаемое редактируемое поле в Angular?

Я реализовал желаемое поведение с директивой: http://jsfiddle.net/fLxjjmb7/3/

Он работает, как задумано, но я чувствую, что должен быть лучший способ сделать это. Есть идеи?

<div ng-app="app" ng-controller="controller"> 
    <div>{{foo}}</div> 
    <button ng-click="increment()">increment</button> 
    <button ng-click="decrement()">decrement</button> 
    <br /> 
    <div shadow="foo"> 
     <input type="text" ng-model="foo" /> 
     <button ng-click="commit()">update</button> 
     <button ng-click="cancel()">cancel</button> 
    </div> 
</div> 
var app = angular.module('app', []); 

var controller = app.controller('controller', function ($scope) { 
    $scope.foo = 1; 
    $scope.increment = function() { ++$scope.foo; }; 
    $scope.decrement = function() { --$scope.foo; }; 
}); 

var directive = app.directive('shadow', function() { 
    return { 
    scope: true, 
    link: function(scope, el, att) { 
     scope.$parent.$watch(att.shadow, function (newValue) { 
      scope[att.shadow] = newValue; 
     }); 

     scope.commit = function() { 
     scope.$parent[att.shadow] = angular.copy(scope[att.shadow]); 
     }; 

     scope.cancel = function() { 
      scope[att.shadow] = angular.copy(scope.$parent[att.shadow]); 
     }; 
    } 
    }; 
}); 

ответ

0

Подумайте, усложняют это немного :)

Вид:

<div ng-controller="ShadowController"> 
    <h1>{{foo}}</h1> 

    <div> 
     <button ng-click="increment()">increment</button> 
     <button ng-click="decrement()">decrement</button> 
    </div> 

    <div> 
     <input type="text" ng-model="tempFoo" /> 
     <button ng-click="commit()">update</button> 
     <button ng-click="cancel()">cancel</button> 
    </div> 
</div> 

Контроллер:

.controller('ShadowController', function ($scope) { 
    $scope.foo = 1; 

    $scope.increment = function() { 
     ++$scope.foo; 
     $scope.cancel(); 
    }; 

    $scope.decrement = function() { 
     --$scope.foo; 
     $scope.cancel(); 
    }; 

    $scope.commit = function() { 
     $scope.foo = parseFloat($scope.tempFoo); 
    }; 

    $scope.cancel = function() { 
     $scope.tempFoo = $scope.foo; 
    }; 

    $scope.cancel(); 
}); 

Еще любителю путь будет следить изменений во временное значение и только enabl e commit/cancel, если есть разница между оригиналом и температурой.

Вид:

<div ng-controller="ShadowControllerAdv"> 
    <h1>{{data.original}}</h1> 

    <div> 
     <button ng-click="increment()">increment</button> 
     <button ng-click="decrement()">decrement</button> 
    </div> 

    <div> 
     <input type="text" ng-model="data.edit" /> 
     <button ng-click="commit()" ng-disabled="!state.hasChanged">update</button> 
     <button ng-click="reset()" ng-disabled="!state.hasChanged">cancel</button> 
    </div> 
</div> 

Контроллер:

.controller('ShadowControllerAdv', function ($scope) { 
    var _dataWatcher; 

    $scope.data = { 
     original: 1 
    }; 

    $scope.state = { 
     hasChanged: false 
    }; 

    function _startWatcher() { 
     _dataWatcher = $scope.$watch('data.edit', function (newValue, oldValue) { 
      if (newValue !== oldValue) { 
       $scope.state.hasChanged = true; 
      } else { 
       $scope.state.hasChanged = false; 
      } 
     }, true); 
    } 

    function _stopWatcher() { 
     if (!_dataWatcher) { 
      return; 
     } 
     _dataWatcher(); 
    } 

    $scope.reset = function() { 
     _stopWatcher(); 
     $scope.data.edit = $scope.data.original; 
     $scope.state.hasChanged = false; 
     _startWatcher(); 
    } 

    $scope.commit = function() { 
     _stopWatcher(); 
     $scope.data.original = parseFloat($scope.data.edit); 
     $scope.reset(); 
    } 

    $scope.increment = function() { 
     $scope.data.original = $scope.data.original + 1; 
     $scope.reset(); 
    }; 

    $scope.decrement = function() { 
     $scope.data.original = $scope.data.original - 1; 
     $scope.reset(); 
    }; 

    $scope.reset(); 
}); 
+0

Хорошая идея. Я должен был упомянуть, что другие компоненты пользовательского интерфейса могут также изменить значение. У них нет доступа для отмены или других локальных функций области. – fixedpoint

+0

Хорошо, если компоненты вне контроллера могут изменить значение, которое вы могли бы поместить логику get/set на заводе. Если объект данных хранится на заводе, метод «get» возвращает полный объект данных, а «set» изменяет data.original - вы должны быть золотыми. Мог бы добавить еще одного слушателя в контроллер, хотя для отслеживания изменений, сделанных в оригинале снаружи, вызовите $ scope.reset(), если это произойдет. –