首页 文章

如何在Angular指令中使用$ compile?

提问于
浏览
0

我有一个500项(人)的集合,我在Angular ng-repeat指令中呈现 . 每个项目都有三个字段(FirstName,LastName,Company) . 我希望用户能够查看详细信息/编辑每个渲染行下面的项目 . 我有一个按钮(Font Awesome square-plus),点击时需要显示项目详细信息/编辑 . 我不想在控制器中包含这个标记/逻辑,因为它已经渲染但隐藏起来很慢...... Chrome中有多秒 . 我认为这是由于所有的 Watch .

为解决此问题,我创建了一个指令,在运行时在当前记录下注入详细信息/编辑项 . 我尝试$编译标记以将其链接到ng-repeat行的当前范围 .

问题..我认为我的范围有问题 . 该指令是ng-repeat块中的引用(p在Persons中),所以我认为我将在指令链接函数中传递记录范围 . 但我只能通过获取父作用域(范围 . $ parent.p而不是scope.p)来获取记录对象 . 我不明白 .

此外,一旦执行了$ compile函数,我确实会在新的详细信息块中看到人员信息 . 但是改变并没有反映在当前的记录数据中,我也没有忽略细节块 .

有什么建议?

标记:

<div class="row" ng-repeat="p in Persons">
    <div class="col-lg-1">
        <i class="fa fa-plus-square" ng-show="!p.showDetail" manage-details></i>
    </div>
    <div class="col-lg-2">{{::p.FirstName}}</div>
    <div class="col-lg-2">{{::p.LastName}}</div>
    <div class="col-lg-2">{{::p.Company}}</div>
    <div id="marker{{$index}}"></div>
    <hr ng-if="!$last" />
</div>

JS:

(function(){

'use strict';

angular
    .module('ngRepeatMystery', [])
    .controller('TestController', TestController)
    .directive('manageDetails', manageDetails);

TestController.$inject = ['$scope'];

function TestController($scope) {

    $scope.Persons = [
        { 'FirstName': 'Joe', 'LastName': 'Delbridge', 'Company': 'Dow', 'showDetail': false },
        { 'FirstName': 'Tony', 'LastName': 'Ingram', 'Company': 'Samtec', 'showDetail': false },
        { 'FirstName': 'Mike', 'LastName': 'Smolinski', 'Company': 'HCHB', 'showDetail': false },
        { 'FirstName': 'Lee', 'LastName': 'Shipman', 'Company': 'Cummins', 'showDetail': false },
        { 'FirstName': 'Eric', 'LastName': 'ONeal', 'Company': 'MSD', 'showDetail': false },
    ];

    $scope.DismissDetails = function (index) {

        $scope.Persons[index].showDetail = false;

        var wrappedMonkey = angular.element($document[0].getElementById('details' + index));
        angular.element(wrappedMonkey).hide();
    }
};

manageDetails.$inject = ['$compile', '$document', '$timeout'];

function manageDetails($compile, $document, $timeout) {

    return {
        restrict: 'A',
        scope: {},
        link: function (scope, element, attrs) {

            element.bind('click', function () {

                // scope.$parent !!?  WAT!
                scope.$parent.p.showDetail = !scope.$parent.p.showDetail;

                if (scope.$parent.p.showDetail) {

                    var index = scope.$parent.$index;

                    var wrappedMarker = angular.element($document[0].getElementById('marker' + index));
                    var details = getDetailsTemplate(index);
                    wrappedMarker.replaceWith(details);

                    var wrappedDetails = angular.element($document[0].getElementById('details' + index));


                    $compile(wrappedDetails.contents())(scope.$parent);

                };
            });
        }
    };

    function getDetailsTemplate(index) {
        var detailsTemplate =
        "<div id=\"details" + index + "\" style=\"padding: 20px;\">" +
                "<div class=\"row\">" +
                    "<div class=\"col-lg-2\"></div>" +
                    "<div class=\"col-lg-8\">" +
                        "<label>Last Name</label>" +
                        "<input ng-model=\"p.LastName\" placeholder=\"Last Name\">
" + "<label>First Name</label>" + "<input ng-model=\"p.FirstName\" placeholder=\"First Name\">
" + "<label>Company</label>" + "<input ng-model=\"p.Company\" placeholder=\"Company\">
" + "<button class=\"btn btn-primary\" ng-click=\"p.DismissDetails($index);\">Done</button>
" + "</div>" + "<div class=\"col-lg-2\"></div>" + "</div>" + "</div>"; return detailsTemplate; } }; })()

Plunker:http://plnkr.co/edit/64TcuhaNi2JcC1hzon15

我也对其他选择开放......

1 回答

  • 1

    好吧,我认为您的代码存在很多问题 .

    我建议不要让指令修改自身之外的东西 .

    正如我之前评论的那样,不要使用$ parent . 只需将数据作为属性传递 . 在调用$ compile时创建一个新的范围,以避免污染现有范围 .

    我修改了你的代码,所以它可以工作,但它仍然不漂亮:

    http://plnkr.co/edit/eLNxewwFzobqTkQ4867n

    HTML:
    
    <div class="row" ng-repeat="p in Persons">
        <div class="col-lg-1">
            <i class="fa fa-plus-square" ng-show="!showDetail" manage-details monkey="p" index="$index" show-detail="showDetail"></i>
        </div>
        <div class="col-lg-2">{{p.FirstName}}</div>
        <div class="col-lg-2">{{p.LastName}}</div>
        <div class="col-lg-2">{{p.Company}}</div>
        <div id="marker{{$index}}"></div>
        <hr ng-if="!$last" />
    </div>
    

    JS:

    return {
            restrict: 'A',
            scope: {
              monkey: '=',
              index: '=',
              showDetail: '='
            },
            link: function (scope, element, attrs) {
                var childScope;
    
                element.bind('click', function () {
    
                    scope.showDetail = !scope.showDetail;
    
                    if (scope.showDetail) {
                        childScope && childScope.$destroy();
                        childScope = scope.$new();
    
                        var index = scope.index;
    
                        var wrappedMarker = angular.element($document[0].getElementById('marker' + index));
                        wrappedMarker.html(getDetailsTemplate(index));
    
                        childScope.p = angular.copy(scope.monkey);
    
                        childScope.dismissDetails = function () {
                            scope.showDetail = false;
                            scope.monkey = angular.copy(childScope.p);
                            wrappedMarker.html('');
                        };
    
                        $compile(wrappedMarker.contents())(childScope);
                    };
                });
            }
        };
    
        function getDetailsTemplate(index) {
            var detailsTemplate =
            "<div id=\"details" + index + "\" style=\"padding: 20px;\">" +
                    "<div class=\"row\">" +
                        "<div class=\"col-lg-2\"></div>" +
                        "<div class=\"col-lg-8\">" +
                            "<label>Last Name</label>" +
                            "<input ng-model=\"p.LastName\" placeholder=\"Last Name\">
    " + "<label>First Name</label>" + "<input ng-model=\"p.FirstName\" placeholder=\"First Name\">
    " + "<label>Company</label>" + "<input ng-model=\"p.Company\" placeholder=\"Company\">
    " + "<button class=\"btn btn-primary\" ng-click=\"dismissDetails();\">Done</button>
    " + "</div>" + "<div class=\"col-lg-2\"></div>" + "</div>" + "</div>"; return detailsTemplate; }

相关问题