如何将属性从控制器范围传递回使用该控制器的指令?

时间:2014-08-11 07:48:16

标签: angularjs angularjs-directive angularjs-scope

我正在尝试创建一个就地编辑指令。我希望能够将它附加到任何类型的元素上,当用户将该元素悬停时,按下按钮时应显示一个编辑按钮,应显示一个文本字段,允许用户更改该字段的内容。

我在传回编辑后的值时遇到了一些麻烦。我怎样才能以某种方式将originalText范围内saEditableController属性的值绑定到saEditable字段?

这是我的代码:

(function() {
    'use strict';

    var app = angular.module('saCommon.editable', []);

    app.controller('saEditableController', ['$scope',
        function($scope) {
            $scope.text = angular.copy($scope.originalText);

            $scope.submit = function() {
                $scope.originalText = $scope.text;
                console.log('In submit: ' + $scope.originalText);
            };
        }
    ]);

    app.directive('saEditable', ['$rootScope', '$timeout', '$compile',
        function($rootScope, $timeout, $compile) {
            return {
                restrict: 'A',

                scope: {
                    'saEditable': '='
                },

                link: function($scope, $element, $attrs) {
                    var $formElement, $inputElement, scope;

                    var onBlur = function() {
                        $formElement.remove();
                        $element.show();
                    };

                    var onKeyPress = function(event) {
                        // Escape pressed
                        if (event.keyCode === 27) {
                            onBlur();
                        }
                        // Enter pressed
                        else if (event.keyCode === 13) {
                            //onBlur();
                        }
                    };

                    var onEdit = function() {
                        $formElement = $('<form ng-submit="submit()"></form>').
                            insertAfter($element).
                            attr('ng-controller', 'saEditableController');

                        $inputElement = $('<input type="text" ng-model="text"></input>').
                            appendTo($formElement).
                            on('blur', onBlur).
                            on('keypress', onKeyPress).
                            width($element.width()).
                            focus();

                        scope = $scope.$new();
                        scope.originalText = $scope.saEditable;

                        $timeout(function() {
                            $compile($formElement)(scope);
                        });

                        $element.hide();
                        return false;                        
                    };

                    var $editIcon = $('<a class="sa-editable-icon" href></a>').
                        hide().
                        on('click', onEdit).
                        appendTo($element);

                    $element.
                        css('position', 'relative').
                        mouseenter(function() {
                            $editIcon.show();
                        }).
                        mouseleave(function() { 
                            $editIcon.hide();
                        });
                }
            };
        }
    ]);

})();

该指令的使用方式如下:

<div sa-editable="collection.description">    
    {{ collection.description }} 
</div>

谢谢!

1 个答案:

答案 0 :(得分:1)

由于您在表单上使用ng-controller,它将创建一个新的子范围,因此您必须建立一种在父范围和子范围之间进行通信的方法。

方法1:在范围内使用scope.$watch()和模型的点符号。

示例Plunker: http://plnkr.co/edit/9MgWucf9JRuFe2A7qhlz?p=preview

不是将originalText直接存储到范围中,而是使用如下对象包装它:

scope = $scope.$new();
scope.formModel = {
  originalText: $scope.saEditable
};

然后您将能够观察到这些变化:

scope.$watch('formModel.originalText', function (value) {
  $scope.saEditable = value;
});

方法2:使用$emit$on即通过事件进行通信。

示例Plunker: http://plnkr.co/edit/4CrcUPy8fk9xrauKLPbx?p=preview

您可以使用$on订阅此类'valueUpdated'事件:

scope = $scope.$new();
scope.originalText = $scope.saEditable;

scope.$on('valueUpdated', function (e, value) {
  e.stopPropagation();
  $scope.saEditable = value;
});

然后$emit来自表单控制器的事件:

$scope.submit = function() {
  $scope.originalText = $scope.text;
  console.log('In submit: ' + $scope.originalText);
  $scope.$emit('valueUpdated', $scope.originalText);
};