scope of event arguments in angular directive

跟風遠走 提交于 2020-01-06 03:25:14

问题


I have the following angular app to create a menu of sections/products.

at present when rendered and hitting the 'add' button that is rendered within each li I want to add a section/product as a sub of that section however multiple new children are created.

ultimately I wish to display a form which when submitted will create the child but that is the next step. Right now I need to limit the scope to the current section and not have multiple bound clicks.

If you need more information please state and I will post in an edit.

Some sample data data.

{
    "sections":[
        {
            "name":"Flags",
            "sections":[
                {
                    "name":"Europe",
                    "sections":[],
                    "products":[
                        { "name": "France" },
                        { "name": "Germany" },
                        { "name": "Ireland" },
                        { "name": "England" }
                    ]
                },
                {
                    "name": "Africa",
                    "sections":[],
                    "products":[
                        { "name": "Egypt" },
                        { "name": "Nigeria" },
                        { "name": "Chad" }

                    ]
                },
                {
                    "name": "South America",
                    "sections":[],
                    "products": [
                        { "name": "Brasil" },
                        { "name": "Argentina" },
                        { "name": "Peru" }
                    ]
                }
            ],
            "products":[]
        },
        {
            "name": "Maps",
            "sections":[
                {
                    "name": "Africa",
                    "sections":[],
                    "products":[
                        { "name": "Egypt" },
                        { "name": "Nigeria" },
                        { "name": "Chad" }

                    ]
                },
                {
                    "name": "South America",
                    "sections":[],
                    "products": [
                        { "name": "Brasil" },
                        { "name": "Argentina" },
                        { "name": "Peru" }
                    ]
                }

            ],
            "products":[]
        }        
    ],
    "products":[]
}

The app.

'use strict';

var menuApp = angular.module('menuApp', []);

menuApp
    .directive('sections', function () {
        return {
            restrict: "E",
            replace: true,
            scope: {
                sections: '='
            },
            template: '<ul><section ng-repeat="section in sections" section="section" /></ul>'
        };
    })
    .directive('section', function ($compile) {
        return {
            restrict: "E",
            replace: true,
            scope: {
                section: '=section'
            },
            template: '<li class="section">{{section.name}} <button ng-click="addSub(section)">Add</button></li>',
            link: function (scope, element, attrs, controller) {
                if (angular.isArray(scope.section.sections)) {
                    element.append("<sections sections='section.sections'></sections>"); 
                    $compile(element.contents())(scope);
                }
                if(angular.isArray(scope.section.products)){
                    element.append("<products products='section.products'></products>"); 
                    $compile(element.contents())(scope);
                };
            },
            controller : function($scope){
                console.log($scope);
                $scope.addSub = function (section){
                    //console.log(section,'Adding Sub');
                    section.sections.push({"name":"Section","sections":[],"products":[]});
                };
            }
        };
    })
    .directive('products', function () {
        return {
            restrict: "E",
            replace: true,
            scope: {
                products: '='
            },
            template: '<ul><product ng-repeat="product in products" product="product"></product></ul>'
        };
    })
    .directive('product', function ($compile) {
        return {
            restrict: "E",
            replace: true,
            scope: {
                product: '='
            },
            template: '<li class="product">{{product.name}}</li>'
        };
    });

menuApp.controller('menuCtrl', function menuCtrl($scope,$http) {
    $http.get('/ajax/getvenuesmenu?venueID='+venueMenu.venueId).success(function(resp) {
        $scope.sections = resp;
    });

    $scope.add = function(data){
        data.push({"name":"Section","sections":[]});
    };   
});

回答1:


Took me a bit to figure it out but here's the basic problem, you are compiling the full contents of section 2 extra times and each compile seems to add a new event handler.

Instead of compiling the contents of element each time you make an append of new template, compile the template itself (outside of the DOM) and then append the compiled template. This way the ng-click handler doesn't get compiled again other than initial scope creation

Here's an abbreviated version with one template appended:

link: function (scope, element, attrs, controller) {
    if (angular.isArray(scope.section.sections)) {
        /* compile outside of the DOM*/
        var subsections = $compile("<sections sections='section.sections'></sections>")(scope);
        /* append compilation*/
        element.append(subsections);        
    }

DEMO

Another approach would be to create a complete template string in link by checking for subsections and products, then compiling everything all at once....instead of using template option

Code for alternate approach compiling complete section at once:

.directive('section', function ($compile, $timeout) {
    return {
        restrict: "E",
        scope: {
            section: '=section'
        },
        link: function (scope, element, attrs, controller) {
            var template = '<li class="section">{{section.name}} <button ng-click="addSub(section)">Add</button>';

            if (angular.isArray(scope.section.sections)) {
                template += "<sections sections='section.sections'></sections>";
            }
            if (angular.isArray(scope.section.products)) {
                template += "<products products='section.products'></products>";
            };

            template += '</li>';

            var compiledTemplate = $compile(template)(scope);
            element.replaceWith(compiledTemplate);

            scope.addSub = function (section) {
                section.sections.push({ "name": "Section", "sections": [], "products": []
                });
            };       
        }
    };
})

DEMO-Alt



来源:https://stackoverflow.com/questions/20461999/scope-of-event-arguments-in-angular-directive

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!