Link to home
Start Free TrialLog in
Avatar of Ahmet Ekrem SABAN
Ahmet Ekrem SABANFlag for Austria

asked on

How to parse HTML content of a variable in Angular.JS?

Hello!

I am new to Angular.JS & are currently working on my first project. I have a page full of entries of the kind
<h1>Title</h1>
<p>Teaser</p>
<p>(a link)</p>

Open in new window


The teaser may include HTML formating or elements like the &amp;. What I want to do is to "parse" this Teaser so that the formating is "understood" properly by the browser (currently Google Chrome).

For the detail page, an id is passed to the shownews, but the first call is without an id to read all the news from where, the user can reach the detail page by each news link. Here, I already head the same problem. Below, you see the Angular.JS code for both the main news page and the detail page. I could solve the problem for the detail page by using the ng-bind-html directive as follows:
controllers.js:
	$scope.shownews = function(id) {

		if (typeof id === 'undefined') {
			$http({
				method: 'GET',
				url: 'http://dev.ivm.at/getallnews.php'
			}).
				success(function(data, status, headers, config) {
					$scope.allnews = data;
					$scope.myHTML = [];

					for (var i = 0; i < $scope.allnews.length; i++) {
						$scope.myHTML[i] = $scope.allnews[i].Teaser;
					}
				});
		} else {
			$http({
				method: 'GET',
				url: 'http://dev.ivm.at/getnews.php?ID=' + id
			}).
				success(function(data, status, headers, config) {
					$scope.singlenews = data;
					$scope.Newstitel = $scope.singlenews[0].Title
					$scope.Bilderlink = $scope.singlenews[0].Bilderlink;
					$scope.Inhalt = $scope.singlenews[0].Inhalt;
					$scope.Teaser = $scope.singlenews[0].Teaser;

					$scope.myHTML = '<h1>' + $scope.Newstitel + '</h1><br>'
						+ '<a href="lighbox mit bild"></a><img alt="" src="'
						+ $scope.Bilderlink + '"><br>'
						/*+ '" style="width:20%;height:20%"><br>'*/
						+ $scope.Inhalt + '</p>';
					//Bilderlink = "http://dev.ivm.at/IVM_APP/uploadlive/graz.JPG"
					//$scope.Bilderlink = $scope.singlenews[0].Bilderlink;
					//usw.
					//Im Array immer 0 weil das der richtige und einzige Datensatz ist.
				});
		}

Open in new window

index.html:
<div data-role="page" id="allnews">
  <div id="sub">
    <section class="blog">
      <article ng-bind-html="myHTML" ng-repeat="news in allnews">
        <h1>{{news.Title}}</h1>
        <p>{{myHTML[$index]}}</p>
        <p class="readmore">
          <a href="onenews" ng-click="shownews(news.ID)">
                  Weiterlesen: {{news.Title}}
          </a>
          <span class="readmore_icon"></span>
        </p>
      </article>
    </section>
  </div>
</div>

Open in new window

My question is how to use the ng-bind-html command properly so that it does parse the $scope.myHTML in the case it is an array of texts.

Thank you for your answer!
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

I am confused about the real intent for your question between "What I want to do is to "parse" this Teaser so that the formating is "understood" properly by the browser (currently Google Chrome)." and "so that it does parse the $scope.myHTML in the case it is an array of texts."

What problem are you seeing with ng-bind-html?  Are you looking for something like ng-bind-html-unsafe (or  $sce.trustAsHtml)?
Avatar of Ahmet Ekrem SABAN

ASKER

Thank you for your reply!

The problem is not that ng-bind-html is not working at all. It is working when $scope.myHTML is a string. What I need is a solution that converts the contents of this variable to HTML when it is an array of strings!!
Would an outer ng-repeat that loops through the array help here?
If it could be possible to change the array contents to HTML, it would. :) What I do not want is to see text like "Home &amp; Outdoor".
If I understand you correctly, I would think that you could create a function in the controller, and process the array, and return a string.

Something like this:

$scope.processHtml = function(html) {
     // Combine HTML
     return combinedHTML
}

Open in new window


and in the view, reference "processHtml(myHTML)".
Thank you for your reply! I added your function to the controller as it is. Here is the code where the myHTML array is accessed, and where I am supposed to use it:
<!-- All news page -->
<div data-role="page" id="allnews">
	<div id="sub">
		<section class="blog">
			<article ng-repeat="news in allnews">
				<h1>{{news.Title}}</h1>
				<p>{{news.Teaser}}</p>
				<p>{{myHTML[$index]}}</p>
				<p class="readmore">
					<a href="#news" ng-click="shownews(news.ID);">
						Weiterlesen: {{news.Title}}
					</a>
					<span class="readmore_icon"></span>
				</p>
			</article>
		</section>
	</div>
</div>

Open in new window

The line with the index is <p>{{myHTML[$index]}}</p>. How do I have to call the function here? As a property of the article tag?
If you add the function to the scope, you should be able to use it like this:

<p>{{myHTML[$index]}}</p>

         becomes

<p>{{processHtml(myHTML)}}</p>
Here are the results...
[...]
<div data-role="page" id="allnews">
	<div id="sub">
		<section class="blog">
			<article ng-repeat="news in allnews">
				<h1>{{news.Title}}</h1>
				<p>{{news.Teaser}}</p>
				<p>{{processHTML(myHTML)}}</p>
				<p class="readmore">
					<a href="#news" ng-click="shownews(news.ID);">
						Weiterlesen: {{news.Title}}
					</a>
					<span class="readmore_icon"></span>
				</p>
			</article>
		</section>
	</div>
</div>
[...]

Open in new window

app.controller("PostsCtrl", function($scope, $http) {
	$http.defaults.useXDomain = true;
	delete $http.defaults.headers.common['X-Requested-With'];

	$scope.processHTML = function(html) {
		// Combine HTML
		return combinedHTML
	}
	[...]

Open in new window

User generated image
Waking up too early means too hasty:

<p>{{processHtml(myHTML)}}</p>

    becomes

<p ng-bind-html="processHtml(myHtml)" />
Good morning, then! :-D

We are approaching! Now, the only unknown is combinedHTML in the processHTML function...
I was guessing at a variable name that you could use to combine the HTML that is in the array.  You could use Array.isArray on the input variable to determine if it is an array, and then use for loop to process each of the HTML elements in the array, and build "combinedHtml".  If the input is a string, just return that value.
Oh, I know what you mean: $scope.myHTML, which is either a string or an array of strings, both with or without HTML tags. I can see in the debugger that the array is returned back by your function, but the information cannot be shown by the browser (Google Chrome). You see, what I need is the content of this array and parsed as HTML.
User generated imageUser generated image
1) You would need to loop through each element in the array, and build a string, that you could return.

2) The debugger indicates that the "html" variable is undefined, which would point to a problem in the view.
OK. I sent you only a part of the code. There is an error message for a missing image and another message that is repeated a lot of times that reads
(257) angular.js:5601 TypeError: a.replace is not a function
    at k (angular-sanitize.min.js:8)
    at z (angular-sanitize.min.js:7)
    at angular-sanitize.min.js:12
    at Object.fn (angular-sanitize.min.js:12)
    at Object.$get.Scope.$digest (angular.js:7790)
    at Object.$get.Scope.$apply (angular.js:7991)
    at done (angular.js:9001)
    at completeRequest (angular.js:9141)
    at XMLHttpRequest.xhr.onreadystatechange (angular.js:9111)(anonymous function) @ angular.js:5601$get @ angular.js:4698$get.Scope.$digest @ angular.js:7802$get.Scope.$apply @ angular.js:7991done @ angular.js:9001completeRequest @ angular.js:9141xhr.onreadystatechange @ angular.js:9111

Open in new window

As there is no reference to my code, I do not know what is the reason for it.

But the all news page runs with the loop that replaces the new line from my last post with
	<article ng-repeat="anHTML in myHTML">
		<!-- p>{{anHTML}}</p -->
		<p ng-bind-html="processHTML(anHTML)" />
	</article>

Open in new window

I added the first line of the loop for test purposes to see, if something is output. Well, the whole array content is output. But the processHTML line does nothing. :-S Now, we are at that point what made me ask for help.

The important point is that, if processHTML would work in this loop properly, I still need a call of the kind <p ng-bind-html="processHTML($index)" /> without a loop, as only one element of the index is required for each news synopsis.

(Most probably, I will return on Monday to work.)
Is this repeat going to always have an array?  Are you always going to next the n-th element from the array?  If so, then I would think that you get away with an ng-bind-html with myHtml[$index].
Hello!

Thank you for your reply! Instead of
<article ng-bind-html="my in myHTML">
	<p>{{my}}</p>
	<p ng-bind-html="processHTML(anHTML)" />
</article>

Open in new window

, I tried the following:

<article ng-repeat="news in allnews"> <h1>{{news.Title}}</h1> <p>{{news.Teaser}}</p> <p ng-bind-html="process(myHTML[$index])"></p> <p class="readmore"> <a href="#news" ng-click="shownews(news.ID);"> Weiterlesen: {{news.Title}} </a> <span class="readmore_icon"></span> </p> </article>
<article ng-repeat="news in allnews"> <h1>{{news.Title}}</h1> <p>{{news.Teaser}}</p> <p ng-bind-html="process($scope.myHTML[$index])"></p> <p class="readmore"> <a href="#news" ng-click="shownews(news.ID);"> Weiterlesen: {{news.Title}} </a> <span class="readmore_icon"></span> </p> </article>
<article ng-repeat="news in allnews"> <h1>{{news.Title}}</h1> <p>{{news.Teaser}}</p> <p>{{$scope.myHTML[$index]}}</p> <p ng-bind-html="process($scope.myHTML[$index])"></p> <p class="readmore"> <a href="#news" ng-click="shownews(news.ID);"> Weiterlesen: {{news.Title}} </a> <span class="readmore_icon"></span> </p> </article>
But I couldn't get what I wanted. It was always like this with the missing third line before the link at the bottom:
User generated image
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Bingo!!!! That is the right answer!

<div data-role="page" id="allnews">
	<div id="sub">
		<section class="blog">
			<article ng-repeat="news in allnews">
				<h1>{{news.Title}}</h1>
				<p ng-bind-html="news.Teaser"></p>
				[...]
			</article>
		</section>
	</div>
</div>

Open in new window