Avoid using extra DOM nodes when using nginclude

后端 未结 5 712
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-31 10:23

I\'m struggling to wrap my mind around how to have an ng-include not use an extra DOM element as I\'m building an angular app from a plain-HTML demo. I\'m working with pretty sl

相关标签:
5条回答
  • 2021-01-31 10:31

    Some of the other answers suggest replace:true, but keep in mind that replace:true in templates is marked for deprecation.

    Instead, in an answer to a similar question, we find an alternative: It allows you to write:

    <div ng-include src="dynamicTemplatePath" include-replace></div>
    

    Custom Directive:

    app.directive('includeReplace', function () {
        return {
            require: 'ngInclude',
            restrict: 'A', /* optional */
            link: function (scope, el, attrs) {
                el.replaceWith(el.children());
            }
        };
    });
    

    (cut'n'paste from the other answer)

    0 讨论(0)
  • 2021-01-31 10:34

    For anyone who happens to visit this question:

    As of angular 1.1.4+ you can use a function in the templateURL to make it dynamic.

    Check out this other answer here

    0 讨论(0)
  • 2021-01-31 10:41

    With the right setup, you can define your own ngInclude directive that can run instead of the one provided by Angular.js and prevent the built-in directive to execute ever.

    To prevent the Angular-built-in directive from executing is crucial to set the priority of your directive higher than that of the built-in directive (400 for ngInclude and set the terminal property to true.

    After that, you need to provide a post-link function that fetches the template and replaces the element's DOM node with the compiled template HTML.

    A word of warning: this is rather draconian, you redefine the behavior of ngInclude for your whole application. I therefore set the directive below not on myApp but inside one of my own directives to limit its scope. If you want to use it application-wide, you might want to make its behavior configurable, e.g. only replace the element if a replace attribute is set in the HTML and per default fall back to setting innerHtml.

    Also: this might not play well with animations. The code for the original ngInclude-directive is way longer, so if you use animations in your application, c&p the original code and shoehorn the `$element.replaceWith() into that.

    var includeDirective = ['$http', '$templateCache', '$sce', '$compile',
                            function($http, $templateCache, $sce, $compile) {
        return {
            restrict: 'ECA',
            priority: 600,
            terminal: true,
            link: function(scope, $element, $attr) {
                scope.$watch($sce.parseAsResourceUrl($attr.src), function ngIncludeWatchAction(src) {    
                    if (src) {
                        $http.get(src, {cache: $templateCache}).success(function(response) {
                            var e =$compile(response)(scope);
                            $element.replaceWith(e);
                        });       
                    }
                }); 
            }
        };
    }];
    
    myApp.directive('ngInclude', includeDirective);
    
    0 讨论(0)
  • 2021-01-31 10:44

    Edit: After some research and for the sake of completeness, I've added some info. Since 1.1.4, the following works:

    app.directive('include',
        function () {
            return {
                replace: true,
                restrict: 'A',
                templateUrl: function (element, attr) {
                    return attr.pfInclude;
                }
            };
        }
    );
    

    Usage:

    <div include="'path/to/my/template.html'"></div>
    

    There is, however, one gotcha: the template cannot be dynamic (as in, passing a variable through scope because $scope, or any DI for that matter, is not accessible in templateUrl - see this issue), only a string can be passed (just like the html snippet above). To bypass that particular issue, this piece of code should do the trick (kudos to this plunker):

    app.directive("include", function ($http, $templateCache, $compile) {
        return {
            restrict: 'A',
            link: function (scope, element, attributes) {
                var templateUrl = scope.$eval(attributes.include);
                $http.get(templateUrl, {cache: $templateCache}).success(
                    function (tplContent) {
                        element.replaceWith($compile(tplContent.data)(scope));
                    }
                );
            }
        };
    });
    

    Usage:

    <div include="myTplVariable"></div>
    
    0 讨论(0)
  • 2021-01-31 10:49

    You can create a custom directive, linking to the template with the templateUrl property, and setting replace to true:

    app.directive('myDirective', function() {
      return {
        templateUrl: 'url/to/template',
        replace: true,
        link: function(scope, elem, attrs) {
    
        }
      }
    });
    

    That would include the template as-is, without any wrapper element, without any wrapper scope.

    0 讨论(0)
提交回复
热议问题