Add html to json content in an NG-Repeat - angularjs

Im repeating objects of JSON using NG-Repeat. How do I include html, such as a link, in here:
{id: "53", description: "here is a <a href = '#/detail/'>Link</a> to something", additional: ["2.jpg", "3.jpg" ]}

You need to use $sce to trust the HTML. I like to create a filter and use ng-bind-html on a <span> tag. Using a filter makes it super simple to show HTML wherever you need. Here is a simple example.
angular.module('app', [])
.filter('unsafe', ($sce) => {
return function(value) {
return $sce.trustAsHtml(value);
}
})
.controller('ctrl', ($scope) => {
$scope.items = [{
id: "53",
description: "here is a <a href = '#/detail/'>Link</a> to something",
additional: ["2.jpg", "3.jpg"]
},
{
id: "54",
description: "here is another <a href = '#/detail/'>Link</a> to something",
additional: ["4.jpg", "5.jpg"]
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<ul>
<li ng-repeat="item in items"><span ng-bind-html="item.description | unsafe"></span></li>
</ul>
</div>

Related

AngularJS doesn't display json object in html after $http.get request

I'm trying to make a get request and display the json data.
Here is the html div tag where the data should be displayed:
<div ng-app="app" ng-controller="searchController">
<ul>
<li ng-repeat="name in datas">
{{ name }}
</li>
</ul>
</div>
And here is the app:
var app = angular.module('app', [
]);
app.factory('getRequest', ($http) => {
function get() {
return $http.get('http://localhost:8080/imagedata/')
.then((response) => {
console.log(response.data);
return response.data;
},
(error) => {
return error.statusText;
});
}
return {
get: get
}
});
app.controller('searchController', ['$scope', 'getRequest', ($scope, getRequest) => {
$scope.datas = getRequest.get();
}]);
Inside factory I have a console.log. The data is shown in console, but not in html view. I can't explain what is happening. The code should be works fine.
It's a little hard to tell what the solution is without seeing your console data. If the data ('datas') displayed in your console is an array of objects, for example something like this...
[
{customerId: '123', name: 'Person1', city: "Toronto"},
{customerId: '456', name: 'Person2', city: "Los Angeles"},
{customerId: '789', name: 'Person3', city: "New York"}
]
you'll want to name the specific properties, like this..
<div ng-app="app" ng-controller="searchController">
<ul>
<li ng-repeat="item in datas">
{{item.name}} <--------------
{{item.customerId}}
{{item.city}}
</li>
</ul>
</div>
I found the solution. As #user2864740 said, in my code I've returned the promise, not a good practice. Passing a promise into ngRepeat here is the solution

Display HTML in AngularJS

I have a angular coding what need insert html tags, I found out I can use ngSanitize :https://docs.angularjs.org/api/ngSanitize , but I don't whant load another library in that project.
I tried this: AngularJS : Render HTML in $scope variable in view
but I could not make work.
It's any way to do this without load another angular library?
html:
<div ng-controller="MyCtrl">
<ul class="procedures">
<li ng-repeat="procedure in procedures">
<h4>{{procedure.icon}}</h4>
<div class="procedure-details" ng-show="show">
<p>text here: {{procedure.text}}</p>
<p>your number is: {{procedure.number}}</p>
<p>price you will pay: {{procedure.price}}</p>
</div>
</li>
</ul>
</div>
js:
var myApp = angular.module('myApp', []);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.procedures = [{
icon: '<i class="fa fa-american-sign-language-interpreting" aria-hidden="true"></i>',
text: 'test text',
number: 1,
price: 10000
}];
}
jsfiddle:
http://jsfiddle.net/wD7gR/247/
Starting from version 1.2.0, angular contains $sce service, that can be used to mark html as "safe"
UPDATED JSFIDDLE
angular
.module('myApp',[])
.controller('MyCtrl', function($scope, $sce) {
$scope.procedures = [
{
icon: $sce.trustAsHtml('<i class="fa fa-american-sign-language-interpreting" aria-hidden="true">i am icon</i>'),
text: 'test text',
number: 1,
price: 10000
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<ul class="procedures">
<li ng-repeat="procedure in procedures">
<h4></h4>
<div class="procedure-details" ng-show="show">
<p>text here: {{procedure.text}}</p>
<p>your number is: {{procedure.number}}</p>
<p>price you will pay: {{procedure.price}}</p>
</div>
</li>
</ul>
</div>
</div>
Instead of using ngSanitize you can use $sce az filter like this:
Put this code in app.js :
app.filter('sce', ['$sce', function ($sce) {
return $sce.trustAsHtml;
}]);
Then use in Html like this:
<h4></h4>
I can tell u that u can do like below It should be as following
$scope.html = "<i class='fa fa-american-sign-language-interpreting' aria-hidden='true'></i>";
and
<div ng-bind-html-unsafe="html"></div>
You can do the same for for icon, text or whatever u like... I'm not sure how to do that right now cuz I'm typing this from mobile fone, i hope u will get the idea, if not plz leave comment and i'll write a full function once i get my hands on machine.
You can use angular-sanitize to insert HTML in a view.
Example is given in plnkr
app.filter("trust", ['$sce', function($sce) {return function(htmlCode){
return $sce.trustAsHtml(htmlCode); }}]);

How to use HTML inside conditional bind in markup

I have markup like this
<p>{{ !job.AdditionalNotes ? "No additional notes." : job.AdditionalNotes }}</p>
Would like to emphasis No Additional notes using something like.
<p>{{ !job.AdditionalNotes ? <em>"No additional notes."</em> : job.AdditionalNotes }}</p>
Is there a way to do this without using ng-if and ng-show to do this retaining the ternary operator?
1st Option
I get this working in the following way (without ng-show or ng-if). I'm using ng-bind-html and $sce service to render the HTML. Since your "no additional notes" message is generic and common, we can easily define in the controller and get it from a method after sanitization.
var app = angular.module("sa", []);
app.controller("FooController", function($scope, $sce) {
$scope.jobs = [{
name: "Sr. Software Developer"
}, {
name: "Software Associates",
AdditionalNotes: "Remote location"
}, {
name: "Front-end developer"
}];
$scope.trust = function(text) {
return $sce.trustAsHtml(text);
};
$scope.noNotesMessage = function() {
return $scope.trust("<em>No additional notes.</em>")
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="sa" ng-controller="FooController">
<ol>
<li ng-repeat="job in jobs">
<strong>{{job.name}}</strong>
<p ng-bind-html="!job.AdditionalNotes ? noNotesMessage() : trust(job.AdditionalNotes)"></p>
</li>
</ol>
</div>
2nd Option
Alternatively, you can write a directive:
var app = angular.module("sa", []);
app.controller("FooController", function($scope, $sce) {
$scope.jobs = [{
name: "Sr. Software Developer"
}, {
name: "Software Associates",
AdditionalNotes: "Remote location"
}, {
name: "Front-end developer"
}];
});
app.directive('notes', function() {
return {
restrict: 'E',
scope: {
additional: '='
},
link: function($scope, element, attr) {
var html = "<p>" + ($scope.additional || "<em>No additional notes.</em>") + "</p>";
element.html(html);
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="sa" ng-controller="FooController">
<ol>
<li ng-repeat="job in jobs">
<strong>{{job.name}}</strong>
<notes additional="job.AdditionalNotes"></notes>
</li>
</ol>
</div>

"htmlToPlaintext" AngularJS (1.3.15) Custom Filter

I am trying to create a custom filter , but despite following the correct structure I think something is wrong.
angular.module('App', [])
.filter("htmlToPlaintext", function() {
return function(text) {
return String(text).replace(/<[^>]+>/gm, '');
}
})
.controller ('mainCtrl',['$scope','$filter', function($scope,$filter){
$scope.items=[
{id: '1', title: '<b>Chicago</b>'},
{id: '2', title: '<b><i>New York</i></b>'},
{id: '3', title: '<div><p>Washington</p></div>'}
];
};
<script src="https://code.angularjs.org/1.3.15/angular.js"></script>
<div ng-app="App">
<div ng-controller="mainCtrl">
<div ng-repeat="item in items">
{{item.title | htmlToPlainText}}
</div>
</div>
</div>
Ideally you should declare your filter within it's own module and then inject it into the App module. But you can attach the filter to the App module directly. Below is a working example:
angular.module('App', [])
.filter("htmlToPlaintext", function() {
return function(input) {
return input.replace(/<[^>]+>/gm, '');
}
})
.controller('mainCtrl', ['$scope',
function($scope) {
$scope.items = [{
id: '1',
title: '<b>Chicago</b>'
}, {
id: '2',
title: '<b><i>New York</i></b>'
}, {
id: '3',
title: '<div><p>Washington</p></div>'
}];
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="App">
<div ng-controller="mainCtrl">
<div ng-repeat="item in items">
{{item.title | htmlToPlaintext}}
</div>
</div>
</div>
You don't need to use $filter as you are using HTML Template Binding.
Extracting text from HTML via Regexps it not good idea. Especially if you encounter with something weird, like this html
<span>2 < 3<span>
Your filter gives you 2, but actually here should be 2 < 3.
If you want to manage all possible cases properly, you should use some DOM-API:
.filter("htmlToPlaintext", function() {
return function(text) {
var div = document.createElement("div");
div.innerHTML = html;
return div.textContent || "";
}
})
Look at this answer for similar question to know more.

How to evaluate stored expression in AngularJS $scope

Please help me in this issue. Following is the the code.
HTML:
<div ng-controller="ctrl">click here</div>
JS:
app.controller('ctrl', function($scope) {
$scope.true_link = "http://google.com";
$scope.link = "{{ true_link }}";
});
Result:
<div ng-controller="ctrl">click here</div>
Expectation:
<div ng-controller="ctrl">click here</div>
Replace {{ link }} by {{ true_link }} in HTML will solve this problem. But I have to use this way. How can I evaluate expression in $scope.link content again? Please help me. Thanks.
Update
Look like facebook, I have two wall pages: User page and Actor page. They have same template structure and process (append, remove element etc...) after bussiness function such as changeAvatar(), changeCover(), post() etc... So I create 'homepage' based directive:
JS
app.directive('homepage', function() {
return {
restrict: 'A',
templateUrl: 'homepage.html',
controller: 'homepageCtrl'
};
});
app.controller('homepageCtrl', function($scope) {
$scope.changeAvatar() = ...;
$scope.post() = ...;
});
and two extend controllers:
app.controller('userCtrl', function($scope, $http) {
$http.({...}).success((data){ $scope.username = data.username })
$scope.menu = [
{
title: "foo-user"
link: "/u/{{ username }}/foo-user"
}
{
title: "bar-user"
link: "/u/{{ username }}/bar-user"
}
]
});
app.controller('actorCtrl', function($scope) {
$http.({...}).success((data){ $scope.actorname = data.actorname })
$scope.menu = [
{
title: "foo-actor"
link: "/u/{{ actorname }}/foo-actor"
}
{
title: "bar-actor"
link: "/u/{{ actorname }}/bar-actor"
}
]
});
HTML
homepage.html
<section>
<header>
<ul class="menu">
<li ng-repeat="_menu in menu">
<a href="{{ _menu.link }}">
{{ _menu.title }}
</a>
</li>
</ul>
</header>
<main>
content...
</main>
</section>
User page:
<div homepage ng-controller="userCtrl"></div>
Actor page:
<div homepage ng-controller="actorCtrl"></div>
Two pages menu has same HTML structure & effect, but differ in items. I wanna define menu item in extended controller (userCtrl, actorCtrl) and print them by ng-repeat. The problem is evaluate $scope.menu.link content.
Solution
I found solution: using $scope.$eval (https://docs.angularjs.org/guide/expression).
In userCtrl, the $scope.menu[i].link is dynamic content because included username - received from ajax call. I can update $scope.menu[i].link in $http.success() by using foreach. But I think using $scope.$eval help me auto update wherever I want easier.
So, the code is:
JS
app.controller('userCtrl', function($scope, $http) {
$http.({...}).success((data){ $scope.username = data.username })
$scope.menu = [
{
title: "foo-user"
link: "'/u/' + username + '/foo-user'"
show: 'true'
}
{
title: "bar-user"
link: "'/u/' + {{ username }} + '/bar-user'"
show: 'username == "lorem"'
}
]
});
HTML
homepage.html
<section>
<header>
<ul class="menu">
<li
ng-repeat="_menu in menu"
>
<a
ng-href="{{$parent.$eval(_menu.link)}}"
ng-show="$parent.$eval(_menu.show)"
>
{{_menu.title}}
</a>
</li>
</ul>
</header>
<main>
content...
</main>
</section>
Create a directive, and use $eval to parse the expression:
app.directive('a', function (){
return {
restrict : 'E',
link: function(scope, element, attr){
element.attr('href',scope.$eval(attr.href));
}
}
});
app.controller('ctrl', function($scope) {
$scope.true_link = "http://google.com";
$scope.link = $scope.true_link; // you need a copy of `$scope.true_link` here
});
<div ng-controller="ctrl"><a ng-href="link">click here</a></div>
$scope.link = "{{ true_link }}"; this is just a string, nothing else, so it will render as such.
Don't be confused by the curly brackets.
You can complicate things by using $compile, eval, etc... or you can simply assign the true_link value to the link variable.
UPDATE
You have a problem in your ng-repeat directive. This:
<li ng-repeat="_menu in menu">
{{ menu.title }}
</li>
Should be this (note _menu):
<li ng-repeat="_menu in menu">
{{ _menu.title }}
</li>
Also, there's no need to use templating in your controller, so this:
$scope.menu = [
{
title: "foo-user"
link: "/u/{{ username }}/foo-user"
}
{
title: "bar-user"
link: "/u/{{ username }}/bar-user"
}
]
can be this:
$scope.menu = [
{
title: "foo-user"
link: "/u/" + $scope.username + "/foo-user"
}
{
title: "bar-user"
link: "/u/" + $scope.username + "/bar-user"
}
]
Why do you want to use {{link}} instead of {{true_link}}? What exactly the issue you've run into that "you have to use this way"? If you can explain this in details, may we can figure out a better solution.

Resources