แทรก HTML ลงในมุมมองจากคอนโทรลเลอร์ AngularJS


800

มันเป็นไปได้ที่จะสร้างHTMLส่วนในการควบคุม AngularJS และมี HTML นี้แสดงให้เห็นในมุมมอง?

สิ่งนี้มาจากข้อกำหนดในการเปลี่ยนหยด JSON ที่ไม่สอดคล้องกันให้เป็นรายการid: valueคู่ที่ซ้อนกัน ดังนั้นHTMLจะถูกสร้างขึ้นในคอนโทรลเลอร์และตอนนี้ฉันต้องการแสดงมัน

ผมได้สร้างสถานที่ให้บริการรูปแบบ แต่ไม่สามารถแสดงผลนี้ในมุมมองโดยไม่ได้เพียงแค่พิมพ์HTML


ปรับปรุง

ปรากฏว่าปัญหาเกิดขึ้นจากการแสดงผลเชิงมุม HTML ที่สร้างขึ้นเป็นสตริงภายในเครื่องหมายคำพูด จะพยายามหาวิธีแก้ไขปัญหานี้

ตัวควบคุมตัวอย่าง:

var SomeController = function () {

    this.customHtml = '<ul><li>render me please</li></ul>';
}

มุมมองตัวอย่าง:

<div ng:bind="customHtml"></div>

ให้:

<div>
    "<ul><li>render me please</li></ul>"
</div>

1
นอกจากนี้โปรดดูคำถามนี้ถามว่าเป็นไปได้ที่จะได้รับสคริปต์ใน HTML แทรกเพื่อให้ทำงาน
enigment

เป็นไปได้หรือไม่ที่จะมีวัตถุหลาย ๆ อันผูกติดกับ ng-bind เดียวกัน? เช่น `` `ng-bind =" site.address_1 site.address_2 site.zip "
fauverism

ถ้าคุณมีจำนวนมากสิ่งที่บนหน้าของคุณคุณจะต้องเปลี่ยนแปลงบรรทัด 15046 ของ angular.js (บ้า) function htmlSanitizer(html) {...ของ ผู้พัฒนาแองกูลาร์ตัดสินใจว่าคุณควรจะสามารถค้นหาการผูก html ใด ๆ โดยค่อย ๆ ผ่านหน้าทั้งหมดของคุณที่ซ่อนองค์ประกอบหนึ่งโดยหนึ่งเพื่อหาชิ้นเดียวที่ขาดหายไปของ html !!! โกรธมากกับข้อสันนิษฐาน !!!
user3338098

ขออภัยคำตอบที่เลือกโดย Luke อาจไม่ใช่คำตอบที่ถูกต้องทั้งหมด คำตอบที่เหมาะสมสามารถพบได้ในคำถามอื่นที่นี่ โดยพื้นฐานแล้ว "ng-bind-html-unsafe แสดงผลเนื้อหาเป็น HTML เท่านั้นโดยจะไม่เชื่อมโยง Angular scope กับ DOM ที่เป็นผลลัพธ์คุณต้องใช้ $ compile service เพื่อจุดประสงค์นั้น"
gm2008

ng-bind ลบ HTML ภายในทั้งหมด ซึ่งไม่ใช่วิธีการทำงานของตัวกรองมันก็โอเคเมื่อตัวกรองเป็นค่าเดียว
Muhammad Umer

คำตอบ:


1120

สำหรับ Angular 1.x ให้ใช้ng-bind-htmlใน HTML:

<div ng-bind-html="thisCanBeusedInsideNgBindHtml"></div>

ณ จุดนี้คุณจะได้รับattempting to use an unsafe value in a safe contextข้อผิดพลาดดังนั้นคุณต้องใช้ngSanitizeหรือ$ sceเพื่อแก้ไขปัญหานั้น

$ SCE

ใช้$sce.trustAsHtml()ในคอนโทรลเลอร์เพื่อแปลงสตริง html

 $scope.thisCanBeusedInsideNgBindHtml = $sce.trustAsHtml(someHtmlVar);

ngSanitize

มี 2 ​​ขั้นตอน:

  1. รวมถึงทรัพยากร angular-sanitize.min.js เช่น:
    <script src="lib/angular/angular-sanitize.min.js"></script>

  2. ในไฟล์ js (คอนโทรลเลอร์หรือมักจะเป็น app.js) ให้รวม ngSanitize เช่น:
    angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ngSanitize'])


30
ใน Angular 1.2 ng-bind-html-unsafeถูกลบออกและคำสั่งทั้งสองถูกรวมกัน ดู: github.com/angular/angular.js/blob/master/…
Sasha Chedygov

60
โดยไม่ต้องใช้ ngSanitize $sceก็สามารถทำได้ในขณะนี้โดยใช้ ฉีดมันเข้าไปในคอนโทรลเลอร์และส่ง html ผ่านมัน $scope.thisCanBeusedInsideNgBindHtml = $sce.trustAsHtml(someHtmlVar);มิฉะนั้นฉันจะได้รับattempting to use an unsafe value in a safe context
Matsemann

3
เราต้องการการทำความสะอาดเล็กน้อยที่นี่ซึ่งเป็นวิธีที่ถูกต้องที่ดูเหมือนว่าจะไม่ทำงานให้ฉัน
ลงจอด

9
stackoverflow.com/questions/21829275/… <- ทำงานให้ฉัน :) ไม่มีตัวเลือกใดในคำตอบที่นี่ทำงานได้อย่างน่าเสียดาย
anpatel

7
เพื่อให้ผู้คนไม่ท้อแท้การอัพเดทล่าสุดของคำตอบนี้ควบคู่ไปกับความต้องการของ ngSanitize ที่ด้านล่างของคำตอบนั้นใช้งานได้จริง
Cull เบ็น

312

คุณสามารถสร้างตัวกรองได้เช่น:

var app = angular.module("demoApp", ['ngResource']);

app.filter("trust", ['$sce', function($sce) {
  return function(htmlCode){
    return $sce.trustAsHtml(htmlCode);
  }
}]);

จากนั้นในมุมมอง

<div ng-bind-html="trusted_html_variable | trust"></div>

หมายเหตุ : ตัวกรองนี้เชื่อถือ html ใด ๆ และทั้งหมดที่ส่งผ่านไปและสามารถแสดงช่องโหว่ XSS หากตัวแปรที่มีการป้อนข้อมูลของผู้ใช้ถูกส่งผ่านไป


@ Katie Astrauskas ขอบคุณสำหรับ anwer! วิธีที่สะอาดมาก การngResourceพึ่งพาBTW ไม่ใช่สิ่งจำเป็น
Athlan

28
ใช้สิ่งนี้เฉพาะเมื่อคุณเชื่อถือ HTML อย่างสมบูรณ์ สิ่งนี้ไม่ได้เป็นการฆ่าเชื้อ HTML ในทางใดทางหนึ่ง แต่อนุญาตให้ Angular สามารถแทรกลงในหน้าเว็บได้ HTML ที่เป็นอันตรายสามารถกระตุ้นการโจมตี XSS
jan.vdbergh

หากประสิทธิภาพมีความสำคัญคุณควรหลีกเลี่ยงการใช้ตัวกรอง ตัวกรองจะทำการย่อยสองครั้งในแต่ละครั้ง
Tantelope

14
ทำไมตัวกรองที่เรียกว่าsanitize? นี่เป็นสิ่งที่ทำให้เข้าใจผิดมากเพราะไม่ได้ทำให้บริสุทธิ์อะไรเลย แต่มันควรจะเรียกว่าtrust, trustSafeหรือสิ่งที่คล้ายกัน
เดนิส Pshenov

1
คำตอบที่ยอดเยี่ยม เป็นชื่อของฉันสำหรับกรองแทนrawHtml sanitize
Wumms

119

Angular JS แสดง HTML ภายในแท็ก

วิธีแก้ปัญหาที่ให้ไว้ในลิงค์ด้านบนใช้งานได้สำหรับฉันไม่มีตัวเลือกใดในชุดข้อความนี้ สำหรับผู้ที่กำลังมองหาสิ่งเดียวกันกับ AngularJS เวอร์ชัน 1.2.9

นี่คือสำเนา:

ตกลงฉันพบวิธีแก้ปัญหาสำหรับสิ่งนี้:

JS:

$scope.renderHtml = function(html_code)
{
    return $sce.trustAsHtml(html_code);
};

HTML:

<p ng-bind-html="renderHtml(value.button)"></p>

แก้ไข:

นี่คือการตั้งค่า:

ไฟล์ JS:

angular.module('MyModule').controller('MyController', ['$scope', '$http', '$sce',
    function ($scope, $http, $sce) {
        $scope.renderHtml = function (htmlCode) {
            return $sce.trustAsHtml(htmlCode);
        };

        $scope.body = '<div style="width:200px; height:200px; border:1px solid blue;"></div>'; 

    }]);

ไฟล์ HTML:

<div ng-controller="MyController">
    <div ng-bind-html="renderHtml(body)"></div>
</div>

7
ระวังให้ดีว่าคุณต้องแน่ใจว่า html นั้นเชื่อถือได้ ไม่เช่นนั้นประตูจะเปิดกว้างสำหรับการโจมตี XSS
jan.vdbergh

วิธีแก้ปัญหานี้โดยใช้ฟังก์ชั่นในการแสดงผล HTML นั้นเป็นวิธีเดียวที่ใช้งานได้สำหรับฉัน
MarceloBarbosa

'$ http' มีไว้เพื่ออะไร
Soldeplata Saketos

@SoldeplataSaketos โดยเฉพาะอย่างยิ่งฉันคิดว่าฉันได้ลองใช้งานในพื้นที่ในเวลานั้นและฉันก็สิ้นสุดการคัดลอกการพึ่งพา
anpatel

อัปเดตคำตอบเดียวกันที่นี่ stackoverflow.com/questions/21829275/…
Surya R Praveen

65

โชคดีที่คุณไม่ต้องการตัวกรองแฟนซีหรือวิธีการที่ไม่ปลอดภัยเพื่อหลีกเลี่ยงข้อความแสดงข้อผิดพลาด นี่คือการใช้งานที่สมบูรณ์เพื่อส่งออกมาร์กอัป HTML อย่างถูกต้องในมุมมองในลักษณะที่ต้องการและปลอดภัย

โมดูล sanitize จะต้องรวมหลังจาก Angular:

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-sanitize.js"></script>

จากนั้นโมดูลจะต้องโหลด:

angular.module('app', [
  'ngSanitize'
]);

สิ่งนี้จะอนุญาตให้คุณรวมมาร์กอัปในสตริงจากคอนโทรลเลอร์คำสั่งและอื่น ๆ :

scope.message = "<strong>42</strong> is the <em>answer</em>.";

ในที่สุดในเทมเพลตจะต้องมีผลลัพธ์เช่น:

<p ng-bind-html="message"></p>

ซึ่งจะผลิตออกที่คาดหวัง: 42เป็นคำตอบ


1
ลองใช้ html เช่น<div><label>Why My Input Element Missing</label><input /></div>... ถ้ามันทำให้คุณประหลาดใจแล้วอัปเดตคำตอบของคุณ .. เพราะฉันทดสอบโซลูชันการโหวต 10 + ทั้งหมด .. วิธีการแก้ปัญหาของคุณไม่ได้ผลสำหรับฉันเพื่อดูแท็กอินพุตของฉัน .. ไม่เช่นนั้น .. ฉันใช้$sce.trustAsHtml(html)
Sami

วิธีนี้ใช้ได้ผลโปรดระมัดระวังการโพสต์ jsfiddle หรือ plunkr?
Pier-Luc Gendreau

นี่น่าจะเป็นคำตอบถ้าใช้มุมล่าสุด
Sandeep

61

ฉันได้ลองวันนี้วิธีเดียวที่ฉันพบคือสิ่งนี้

<div ng-bind-html-unsafe="expression"></div>


6
ควรใช้โซลูชันนี้เฉพาะเมื่อแหล่งที่เชื่อถือได้เพื่อหลีกเลี่ยงการโจมตีด้วยสคริปต์ข้ามไซต์
Bertrand

3
ในฐานะของ Angular 1.0.2 สิ่งนี้ใช้ได้กับฉันโดยไม่ต้องใช้ไฟล์หรือการเชื่อมต่ออื่นใด
enigment

1
การใช้ Angular 1.0.8 และมันใช้งานได้สำหรับฉัน คำเตือนของ Heed @ Bertrand ต้องแน่ใจว่าคุณเชื่อถือแหล่งที่มา
Jack Slingerland

12
สำหรับการอ้างอิงในอนาคต ng-bind-html-unsafe ถูกลบในรุ่น 1.2 ตอนนี้คุณต้องใช้โมดูล ngSanitize และผูก html ที่ไม่ปลอดภัยคุณควรใช้วิธี $ sce.trustAsHtml
Lucas Lazaro

53

ng-bind-html-unsafe ไม่ทำงานอีกต่อไป

นี่คือวิธีที่สั้นที่สุด:

สร้างตัวกรอง:

myApp.filter('unsafe', function($sce) { return $sce.trustAsHtml; });

และในมุมมองของคุณ:

<div ng-bind-html="customHtml | unsafe"></div>

PS วิธีการนี้ไม่ต้องการให้คุณรวมngSanitizeโมดูล


3
นี่เป็นทางออกที่ดีที่สุดที่ฉันเคยเห็นสำหรับ Angular 1.2 โซลูชันที่ใช้$sceในคำตอบที่ยอมรับนั้นใช้ไม่ได้สำหรับฉันและฉันไม่ต้องการรวมการพึ่งพาเพิ่มเติมสำหรับสิ่งเล็กน้อยดังนั้น
Daniel Bonnell

ทางออกของ Bidhan Bhattarai นั้นใช้ได้สำหรับฉัน เชิงมุม 1.6.1
mediaguru

25

บน html

<div ng-controller="myAppController as myCtrl">

<div ng-bind-html-unsafe="myCtrl.comment.msg"></div>

หรือ

<div ng-bind-html="myCtrl.comment.msg"></div

บนคอนโทรลเลอร์

mySceApp.controller("myAppController", function myAppController( $sce) {

this.myCtrl.comment.msg = $sce.trustAsHtml(html);

ยังทำงานร่วมกับ $scope.comment.msg = $sce.trustAsHtml(html);


1
$sceเรียบร้อย แต่ผู้ใช้ไม่สามารถเพิ่มเบรกพอยต์ที่นี่และกู้คืนรหัสที่เป็นอันตรายใด ๆ เพื่อthis.myCtrl.comment.msgใช้ดีบักเกอร์ได้หรือไม่
BradGreens

จากนั้นอีกครั้ง BradGreens คุณจะสามารถทำเช่นเดียวกันกับ ng-bind-html-unsafe ได้หรือไม่?
CodeOverRide

4
หากใครต้องการแฮ็คเบราว์เซอร์ของตนเองก็สามารถทำได้ใครจะสนใจ จะไม่มีผลกับผู้ใช้รายอื่น @BradGreens นั่นเป็นคำถามหรือไม่
Chris Stephens

@ChrisStephens คุณถูกต้อง ฉันเดาว่าจะตอบคำถามของฉัน แต่ความคิดเห็นของฉันคือคุณสมบัติเหล่านี้ใกล้เคียงกับความปลอดภัยที่รับรู้มากกว่าความปลอดภัยที่แท้จริง บางทีมันอาจป้องกันการโจมตีอัตโนมัติบางประเภท? ฉันไม่เคยเข้าใจอย่างชัดเจนว่าทำไมการทำสิ่งนี้จึงช่วยแอพได้ แอพของฉันต้องเพิ่มตัวกรองไปยังอินสแตนซ์ทุกครั้งของการแสดงผล wysiwyg HTML เพราะอาจมีอินไลน์ CSS ซึ่งng-bind-htmlตัดออก
BradGreens

1
คุณสมบัติเหล่านี้จะช่วยลดข้อผิดพลาดในการเข้ารหัสอย่างปลอดภัย โดยเฉพาะอย่างยิ่งปัญหาเกี่ยวกับการฉีดมาร์กอัป / รหัส โดยค่าเริ่มต้นข้อมูลที่ถูกผูกไว้ทั้งหมดจะถูกเข้ารหัสเพื่อแสดง ดังนั้นโดยทั่วไปถ้าคุณต้องการที่จะแสดงผลมาร์กอัปสิ่งนี้บังคับให้คุณคิดเกี่ยวกับสิ่งที่คุณพยายามทำ หากไม่มีคุณสมบัติเหล่านี้คุณสามารถทำอะไรได้มากมายกับการรักษาความปลอดภัยฝั่งเซิร์ฟเวอร์เพียงอย่างเดียว แต่เพื่อแยกความกังวลแอปไคลเอ็นต์ควรคิดค่าใช้จ่ายในการจัดการข้อมูลที่ถูกต้องสำหรับการแสดงผล
Chris Stephens

9

ฉันพบว่าการใช้ ng-sanitize ไม่อนุญาตให้ฉันเพิ่ม ng-click ใน html

เพื่อแก้ปัญหานี้ฉันได้เพิ่มคำสั่ง แบบนี้:

app.directive('htmldiv', function($compile, $parse) {
return {
  restrict: 'E',
  link: function(scope, element, attr) {
    scope.$watch(attr.content, function() {
      element.html($parse(attr.content)(scope));
      $compile(element.contents())(scope);
    }, true);
  }
}
});

และนี่คือ HTML:

<htmldiv content="theContent"></htmldiv>

โชคดี.


6

เพียงแค่ทำอย่างนี้ใช้ ngBindHtml โดยทำตามเชิงมุม (v1.4) เอกสาร ,

<div ng-bind-html="expression"></div> 
and expression can be "<ul><li>render me please</li></ul>"

ตรวจสอบให้แน่ใจว่าคุณรวม ngSanitize ในการอ้างอิงของโมดูล จากนั้นควรทำงานได้ดี


4

โซลูชันอื่นซึ่งคล้ายกับ blrbr's มากยกเว้นการใช้แอ็ตทริบิวต์ที่กำหนดขอบเขตคือ:

angular.module('app')
.directive('renderHtml', ['$compile', function ($compile) {
    return {
      restrict: 'E',
      scope: {
        html: '='
      },
      link: function postLink(scope, element, attrs) {

          function appendHtml() {
              if(scope.html) {
                  var newElement = angular.element(scope.html);
                  $compile(newElement)(scope);
                  element.append(newElement);
              }
          }

          scope.$watch(function() { return scope.html }, appendHtml);
      }
    };
  }]);

และจากนั้น

<render-html html="htmlAsString"></render-html>

หมายเหตุคุณอาจแทนที่element.append()ด้วยelement.replaceWith()


3

มีวิธีแก้ปัญหาอีกหนึ่งข้อสำหรับปัญหานี้โดยใช้การสร้างแอตทริบิวต์ใหม่หรือคำสั่งเป็นมุม

ผลิตภัณฑ์ specs.html

 <h4>Specs</h4>
        <ul class="list-unstyled">
          <li>
            <strong>Shine</strong>
            : {{product.shine}}</li>
          <li>
            <strong>Faces</strong>
            : {{product.faces}}</li>
          <li>
            <strong>Rarity</strong>
            : {{product.rarity}}</li>
          <li>
            <strong>Color</strong>
            : {{product.color}}</li>
        </ul>

app.js

 (function() {
var app = angular.module('gemStore', []);    
app.directive("     <div ng-show="tab.isSet(2)" product-specs>", function() {
return {
  restrict: 'E',
  templateUrl: "product-specs.html"
};
});

index.html

 <div>
 <product-specs>  </product-specs>//it will load product-specs.html file here.
 </div>

หรือ

<div  product-specs>//it will add product-specs.html file 

หรือ

<div ng-include="product-description.html"></div>

https://docs.angularjs.org/guide/directive


3

คุณยังสามารถใช้NG- ได้แก่

<div class="col-sm-9 TabContent_container" ng-include="template/custom.html">
</div>

คุณสามารถใช้"ng-show"เพื่อแสดงซ่อนข้อมูลเทมเพลตนี้


คุณแน่ใจหรือว่านี่คือทั้งหมดที่คุณต้องทำเพื่อที่จะใช้ ng-include?
ลัทธิลัทธิฟอเรสต์

ใช่ .. ฉันได้ลองแล้ว และถ้าคุณใช้เทมเพลตให้ใช้วิธีดังต่อไปนี้ - <script type = "text / ng-template" id = "custom.html">
Vikash Sharma

2

นี่คือวิธีทำตัวกรองเช่นนี้

.filter('trusted',
   function($sce) {
     return function(ss) {
       return $sce.trustAsHtml(ss)
     };
   }
)

และใช้สิ่งนี้เป็นตัวกรองกับ ng-bind-html like

<div ng-bind-html="code | trusted">

และขอบคุณ Ruben Decrop


1

ใช้

<div ng-bind-html="customHtml"></div>

และ

angular.module('MyApp', ['ngSanitize']);

เพื่อที่คุณจะต้องรวมangular-sanitize.jsเช่นในไฟล์ html ของคุณด้วย

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular-sanitize.js"></script>

0

นี่เป็นbind-as-htmlคำสั่งง่ายๆ (และไม่ปลอดภัย) โดยไม่จำเป็นต้องngSanitize:

myModule.directive('bindAsHtml', function () {
    return {
        link: function (scope, element, attributes) {
            element.html(scope.$eval(attributes.bindAsHtml));
        }
    };
});

โปรดทราบว่านี่จะเปิดขึ้นสำหรับปัญหาด้านความปลอดภัยหากเชื่อมโยงเนื้อหาที่ไม่น่าเชื่อถือ

ใช้อย่างนั้น:

<div bind-as-html="someHtmlInScope"></div>

-1

ตัวอย่างการทำงานกับไปป์เพื่อแสดง html ในเทมเพลตที่มี Angular 4

1.Crated Pipe escape-html.pipe.ts

`

import { Pipe, PipeTransform } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
@Pipe({name : 'keepHtml', pure : false})
export class EscapeHtmlPipe implements PipeTransform{
 constructor(private sanitizer : DomSanitizer){
 }
 transform(content){
  return this.sanitizer.bypassSecurityTrustHtml(content);
 }
}

`2. ลงทะเบียนไพพ์ไปที่ app.module.ts

 import {EscapeHtmlPipe} from './components/pipes/escape-html.pipe';
    declarations: [...,EscapeHtmlPipe]
  1. ใช้ในเทมเพลตของคุณ

        <div class="demoPipe"  [innerHtml]="getDivHtml(obj.header) | keepHtml">

  2. getDivHtml() { //can return html as per requirement}

    โปรดเพิ่มการใช้งานที่เหมาะสมสำหรับ getDivHtml ในไฟล์ component.ts ที่เกี่ยวข้อง


1
ฉันคิดว่าเขาทำงานกับ AngularJS ไม่ใช่เวอร์ชันที่ใหม่กว่า
โรคเรื้อน

-1

ใช้ง่ายเพียงแค่[innerHTML]ด้านล่าง:

<div [innerHTML]="htmlString"></div>

ก่อนที่คุณจะต้องใช้ng-bind-html...


มีให้เฉพาะภายใน Angular (Angular version 2+) ไม่ใช่ AngularJS (Angular version 1)
ste2425

-1

ใน Angular 7 + ionic 4 สามารถแสดงเนื้อหา Html ได้โดยใช้ "[innerHTML]":

<div [innerHTML]="htmlContent"></div>

ฉันหวังว่านี่จะช่วยคุณได้ ขอบคุณ


กรุณาบอกฉันว่ามีอะไรผิดปกติในรหัสนี้ซึ่งเป็นสาเหตุให้ downvote โพสต์นี้ ฉันทดสอบโค้ดนี้ในแอปพลิเคชั่น 2 ตัวของฉันแล้ว มันได้ผล. กรุณาแบ่งปันประสบการณ์ของคุณ ขอบคุณมาก.
Kamlesh

1
AngularJS เท่ากับ Angular 1.x Angular 7 เป็นเฟรมเวิร์กที่แตกต่างอย่างสิ้นเชิง
Aw Snap
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.