แทนที่ ng-include node ด้วย template?


85

ยังใหม่กับเชิงมุม เป็นไปได้หรือไม่ที่จะแทนที่โหนด ng-include ด้วยเนื้อหาของเทมเพลตที่รวมอยู่ ตัวอย่างเช่นด้วย:

<div ng-app>
    <script type="text/ng-template" id="test.html">
        <p>Test</p>
    </script>
    <div ng-include src="'test.html'"></div>
</div>

html ที่สร้างขึ้นคือ:

<div ng-app>
    <script type="text/ng-template" id="test.html">
        <p>Test</p>
    </script>
    <div ng-include src="'test.html'">
        <span class="ng-scope"> </span>
        <p>Test</p>
        <span class="ng-scope"> </span>
    </div>
</div>

แต่สิ่งที่ฉันต้องการคือ:

<div ng-app>
    <script type="text/ng-template" id="test.html">
        <p>Test</p>
    </script>
    <p>Test</p>
</div>

1
ลบเครื่องหมายคำพูดเดียวออก'test.html'เพื่อใช้เทมเพลตแทนที่จะใช้ url
charlietfl

1
อ่านความคิดเห็นของ doc สำหรับ ng-include ดูเหมือนว่ามันจะล้อมรอบสตริงด้วยเครื่องหมายคำพูดเดี่ยวสำหรับเทมเพลตและไม่มี url นอกจากนี้คำถาม stackoverflow
SunnySydeUp

คุณกำลังอ่านเอกสารและโพสต์ที่คุณเชื่อมโยงไปข้างหลัง
charlietfl

คำตอบ:


134

ฉันมีปัญหาเดียวกันนี้และยังคงต้องการให้คุณสมบัติของ ng-include รวมเทมเพลตไดนามิก ฉันกำลังสร้างแถบเครื่องมือ Bootstrap แบบไดนามิกและฉันต้องการมาร์กอัปที่สะอาดกว่าเพื่อให้ใช้สไตล์ CSS ได้อย่างถูกต้อง

นี่คือวิธีแก้ปัญหาที่ฉันคิดขึ้นสำหรับผู้ที่สนใจ:

HTML:

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

คำสั่งที่กำหนดเอง:

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

หากใช้โซลูชันนี้ในตัวอย่างข้างต้นการตั้งค่า scope.dynamicTemplatePath เป็น "test.html" จะทำให้ได้มาร์กอัปที่ต้องการ


ต้องใช้มุม v1.2 +
colllin

ฉันได้อ้างถึงคำตอบนี้ในคำถามที่คล้ายกัน: angularjs - หลีกเลี่ยงการใช้โหนด DOM เพิ่มเติมเมื่อใช้ nginclude - Stack Overflow
Peter V.Mørch

สิ่งนี้ใช้ได้กับเชิงมุม 1.2.5+ สำหรับ 1.2.4 ถ้าคุณมี ng-include ที่ ng-include อีกอันหนึ่งจะล้มเหลว ฉันเดาว่าเป็นเพราะ# 5247แต่ฉันไม่แน่ใจ ดูChangelogด้วยตัวคุณเอง นี่คือPlunkr ที่แสดงให้เห็นถึงปัญหานี้ด้วย 1.2.4 (เปลี่ยนเป็นเชิงมุม 1.2.5 และดูว่าใช้งานได้! :-)
Peter V.Mørch

9
โปรดทราบว่าการจัดการ DOM ดังกล่าวค่อนข้างแฮ็กมีปัญหาหากองค์ประกอบรูทของเทมเพลตที่รวมใช้บางอย่างเช่น ng-repeat จะไม่สามารถแทรกผลลัพธ์ใน DOM
Guria

1
โปรดดูคำตอบของฉันสิ่งนี้จะล้มเหลวเนื่องจากฟังก์ชัน prelink จะทำงานในองค์ประกอบลูกแล้ว
Sai Dubbaka

28

ขอบคุณ @ user1737909 ทำให้ฉันรู้ว่า ng-include ไม่ใช่ทางที่จะไป แนวทางเป็นแนวทางที่ดีกว่าและชัดเจนกว่า

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

App.directive('blah', function() {
    return {
        replace: true,
        restrict: 'E',  
        templateUrl: "test.html"
    };
});

ใน html:

<blah></blah>

2
ขอบคุณ! กำลังมองหาวิธีแก้ปัญหาแบบ ng-include แต่สิ่งนี้ช่วยให้ฉันรู้ว่าคำสั่งนั้นดีกว่า
Matt Kim

โปรดทราบว่าreplace:trueแม่จะทำเครื่องหมายสำหรับการเลิกใช้ ฉันจะหลีกเลี่ยงการใช้โซลูชันนี้เนื่องจากสถานะการเลิกใช้งาน
Peter V.Mørch

@ PeterV.Mørchขอบคุณ สำหรับผู้ที่สนใจนี่คือการกระทำ: github.com/angular/angular.js/commit/… . ดูเหมือนว่าจะเลิกใช้แล้วเนื่องจากมีความซับซ้อน (และอาจเป็นเหตุผลอื่น ๆ )
SunnySydeUp

15

ฉันมีปัญหาเดียวกันสไตล์ชีต css บุคคลที่สามของฉันไม่ชอบองค์ประกอบ DOM เพิ่มเติม

วิธีแก้ปัญหาของฉันง่ายมาก เพียงแค่เลื่อน ng-include 1 ขึ้นไป ดังนั้นแทนที่จะเป็น

<md-sidenav flex class="md-whiteframe-z3" md-component-id="left" md-is-locked-open="$media('gt-md')">
  <div ng-include="myService.template"></span>
</md-sidenav>

ฉันแค่ทำ:

<md-sidenav flex class="md-whiteframe-z3" md-component-id="left" md-is-locked-open="$media('gt-md')" ng-include="myService.template">
</md-sidenav>

ฉันพนันได้เลยว่าสิ่งนี้จะได้ผลในสถานการณ์ส่วนใหญ่แม้ว่าในทางเทคนิคจะไม่ใช่สิ่งที่คำถามกำลังถามก็ตาม


10

อีกทางเลือกหนึ่งคือการเขียนคำสั่งแทนที่ / รวมง่ายๆของคุณเองเช่น

    .directive('myReplace', function () {
               return {
                   replace: true,
                   restrict: 'A',
                   templateUrl: function (iElement, iAttrs) {
                       if (!iAttrs.myReplace) throw new Error("my-replace: template url must be provided");
                       return iAttrs.myReplace;
                   }
               };
           });

จากนั้นจะใช้ดังนี้:

<div my-replace="test.html"></div>

9

นี่คือวิธีการเปลี่ยนลูกที่ถูกต้อง

angular.module('common').directive('includeReplace', function () {
    return {
        require: 'ngInclude',
        restrict: 'A',
        compile: function (tElement, tAttrs) {
            tElement.replaceWith(tElement.children());
            return {
                post : angular.noop
            };
        }
    };
});

4
html บางส่วนที่รวมไว้ของฉันมี ng-repeat และนี่คือคำตอบเดียวที่แก้ไขได้! ขอบคุณมาก.
Saad Benbouzid

ฉันต้องย้ายเนื้อหาฟังก์ชันจากcompileไปยังlinkเนื่องจากองค์ประกอบของฉันว่างเปล่าในระหว่างขั้นตอนการคอมไพล์
itachi

3

คำสั่งต่อไปนี้จะขยายฟังก์ชันคำสั่ง ng-include

เพิ่มตัวฟังเหตุการณ์เพื่อแทนที่องค์ประกอบดั้งเดิมเมื่อเนื้อหาพร้อมและโหลด

ใช้แบบเดิมเพียงเพิ่มแอตทริบิวต์ "แทนที่":

<ng-include src="'src.html'" replace></ng-include>

หรือด้วยสัญกรณ์แอตทริบิวต์:

<div ng-include="'src.html'" replace></div>

นี่คือคำสั่ง (อย่าลืมรวมโมดูล 'รวม - แทนที่' เป็นการอ้างอิง):

angular.module('include-replace', []).directive('ngInclude', function () {
    return {
        priority: 1000,
        link: function($scope, $element, $attrs){

            if($attrs.replace !== undefined){
                var src = $scope.$eval($attrs.ngInclude || $attrs.src);

                var unbind = $scope.$on('$includeContentLoaded', function($event, loaded_src){
                    if(src === loaded_src){
                        $element.next().replaceWith($element.next().children());
                        unbind();
                    };
                });
            }
        }
    };
});

2

ฉันจะไปกับโซลูชันที่ปลอดภัยกว่าโซลูชันที่จัดทำโดย @Brady Isom

ฉันชอบที่จะพึ่งพาonloadตัวเลือกที่กำหนดng-includeเพื่อให้แน่ใจว่าโหลดเทมเพลตแล้วก่อนที่จะพยายามลบ

.directive('foo', [function () {
    return {
        restrict: 'E', //Or whatever you need
        scope: true,
        template: '<ng-include src="someTemplate.html" onload="replace()"></ng-include>',
        link: function (scope, elem) {
            scope.replace = function () {
                elem.replaceWith(elem.children());
            };
        }
    };
}])

ไม่จำเป็นต้องมีคำสั่งที่สองเนื่องจากทุกอย่างได้รับการจัดการภายในคำสั่งแรก


ระวังว่าด้วยเชิงมุม 1.5 ลูกคนแรกในองค์ประกอบคำสั่งคือความคิดเห็น ดังนั้นฉันจึงแน่ใจว่าฉันได้รับองค์ประกอบ ng-include แล้วแทนที่ด้วยลูก ๆ ของมัน: let ngInclude = angular.element( element[ 0 ].querySelector( 'ng-include' ) ); ngInclude.replaceWith( ngInclude.children() );
Mattijs
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.