对指令的更改不会传播到父作用域

时间:2015-09-18 08:26:02

标签: javascript angularjs

我试图实施一种"回滚"特征。这就是我所拥有的:

从一个非常简单的对象开始:

var allMetals = [
    {name: "Gold", rating: 9},
    {name: "Silver", rating: 8},
    {name: "Copper", rating: 7}];

他们可以编辑。我有一个处理编辑的指令。显示的列表如下:

<ul>
    <li ng-repeat="m in allMetals">
        {{m.name}} 
        <span>{{m.rating}}</span>
        <a href="" ng-click="edit(m.name)"</a>
    </li>
</ul>

转发器标记:

<div edit-metal="" metal="currentMetal" ng-show="editing"></div>

在编辑功能中,我只是设置currentMetal设置标志的值,以便编辑指令变为可见。

function edit(name) {
    $scope.currentMetal = helper.getMetalByName(name);
    $scope.editing = true;
}

现在,在指令中,我有一个简单的文本框,它绑定到模型,当用户编辑时,我可以看到父范围var正在更新,一切都很花哨。 但有时,在编辑之后,我可能会改变主意并决定取消更改。所以我有一个取消功能就是这样做的。

// in the directive link()
var uneditedMetal = _.clone($scope.metal); 

$scope.cancel = function(){
    $scope.metal = uneditedMetal;       
}

$scope.save = () {
    //do nothing as parent handles save with a different user button
}

现在,为了实现这一点,我必须在用户每次点击“编辑”时更新指令的currentMetal值,以便我可以在之前对其进行备份它的编辑;如果点击取消按钮。我尝试使用$scope.$watch('metal', function(){ /*clone here*/ })进行此操作,但似乎触发了太多次,所以现在我在父{q} edit()函数上广播并使用$scope.$on()复制值的备份。

我不确定这是实现这一目标的最佳方式,如果您有任何建议请告诉我。

我的问题是,当调用cancel()时,我知道正在设置的值是正确的值,它会更改指令中的值,但它不会传播到父作用域! 即使奇怪的是,如果我只是$scope.metal = uneditedMetal而不是使用$scope.metal.name = "Mercury"进行复制,那么这种变化就会被传播,但是对象分配和其他_.clone()都不起作用。我不太清楚失去的变化在哪里。有任何想法吗?

这是一个复制我的问题的plnkr:http://plnkr.co/edit/VKLr8gMVLyYkNvJJOGKa?p=preview

任何见解都将不胜感激,谢谢。

重现问题的步骤

  1. 编辑列表中的任何项目
  2. 修改文本框中的任何值(并观察父列表更改)
  3. 点击取消。
  4. 我希望在点击取消时还原父更改,但它不会发生。

1 个答案:

答案 0 :(得分:0)

我编写了内联编辑指令,它执行与您正在执行的操作相同的操作,编辑和取消编辑功能。 您可以将此指令用作:

<inline-edit 
  ng-model="yourmodel" 
  input-type="'text'" 
  label="your label'"
  label-width="3"
  input-width="9"             
  isdisabled="true">
</inline-edit>

angular.module('common.inlineEdit', [])

.directive('inlineEdit', ['$compile', '$timeout', function ($compile, $timeout ) {
  return {
      require: "ngModel",
      restrict: 'E',
      replace: true,
      scope: {
          updateFn: '&',
          isdisabled: '=',
          inputType: '=',
          label: '=',
          labelWidth: '=',
          inputWidth: '='
      },
      templateUrl: "directives/inlineEdit/inlineEdit.tpl.html",
      link: function(scope, elm, attrs, ngModel) {
        scope.model = {};
        var cancelEditTimer;
        ngModel.$render = function() {
          scope.model.value = ngModel.$viewValue;
        };
        scope.cancelEdit = function () {
          cancelEditTimer = $timeout(function(){
                              scope.model.value = ngModel.$viewValue;
                              scope.editing = false;
                            },300);
        };
        scope.saveEdit = function () {
          scope.editing = false;
          scope.updateFn({value: scope.model.value});
        };
        scope.edit = function () {
          scope.editing=true;
                  $timeout(function(){
                      scope.input = (elm[0].querySelector('input[type="text"]'));
                    scope.input.focus();
                  },100);      	
        };
        scope.select = function () {
                  $timeout(function(){
                    scope.editing=true;
                    $timeout.cancel(cancelEditTimer);
                  },10); 
        };
      }
  };
}]);

指令的模板文件是:

<div ng-mouseover="showEdit = true" ng-mouseleave="showEdit = false" class="row inline-edit">
	<div class="col-sm-{{labelWidth}}">
		<b>{{label}} </b>
	</div>
	<div class="col-sm-{{inputWidth}}">
		<span ng-show="!editing">{{model.value}} </span>
		<a href="javascript:void(0);" class="fa fa-pencil-square-o edit" ng-show="!isdisabled && showEdit && !editing" ng-click="edit()"></a>
		<div class="row">
			<div class="col-sm-8" ng-if="editing && inputType=='text'">
				<input type="text" ng-model="model.value" class="form-control input-sm" ng-blur="cancelEdit()">
			</div>
			<div class="col-sm-4 action-buttons"> 
				<a class="fa fa-check save" href="javascript:void(0);" ng-click="saveEdit()" ng-show="editing"></a>
				<a class="fa fa-times cancel" href="javascript:void(0);" ng-click="cancelEdit()" ng-show="editing"></a>
			</div>
		</div>
	</div>
</div>