Format a text before displaying it in Angularjs - angularjs

I have a text like:
Blablabla
Hello
How are you?
But it has to be stored in my database in the same text field like this:
Blablabla Hello How are you?
I am using Angular and I would like to know how to format the database text before displaying it inside the template like this.
<p>{{ value }}</p>
I know I should add a separator in the database but I don't know if it's possible to add a '\n' for example and then format the text before displaying it.

Try this
In your controller
$scope.value = $scope.value.replace(/\n/g, '<br/>');
$scope.trustedHtml = $sce.trustAsHtml($scope.value);
in your view
<p ng-bind-html="trustedHtml"></p>
OR
you can create a factory to use it everywhere
angular.module('app').filter('trustedHtml', function($sce) {
return function(val) {
return $sce.trustAsHtml(val);
};
});
In your controller
$scope.value = $scope.value.replace(/\n/g, '<br/>');
in your view
<p ng-bind-html="value | trustedHtml"></p>
SOLUTION:
<p ng-bind-html="value"></p>
So Angular $sanitize deletes the tags that may be malicious like 'script'

Related

How to make HTML markup show correctly in AngularJS binding using a function?

I have following code, to illustrate an issue I have:
<p>{{'This is spaced'}}</p>
<p>This is spaced</p>
<p>{{leerlingController.myReplace('This is spaced')}}</p>
The first and second line appear as intended, showing spaces instead of codes. The third line however shows the & nbsp; codes instead of the spaces.
the function is in a controller, simply:
vm.myReplace = function(item) {
return item.replace(/ /g, ' ');
}
How to make this function work as intended? (I need it to modify text in select-options attached to a ngRepeater.)
This is a security restriction from Angular, see docs here.
You could use ng-bind-html and load ngSanitize module. Or use $sce.trustAsHtml(value) in your method if you don't want to load ngSanitize.
Then it would look like this ($sce is dep. injected into controller):
vm.myReplace = function(item) {
return $sce.trustAsHtml(item.replace(/ /g, ' '));
};
Please have a look at the demo below or this fiddle.
Update 12.06.2016:
I'm not sure if there is an easier way of doing this. But you could check each column and calculate the required padding.
For adding the padding I've used underscore.string.
Also use ng-repeat so you can use ng-bind-html and to have the correct spacing you should use a monospaced font e.g. Lucida Console or Courier (see css style in the fiddle).
Here you can find a fiddle for this.
Another way of doing this would be to create a directive that is styled like a select-tag then you could use a table inside of the dropdown to have the correct spacing.
Update 12.06.2016 - 21:25 (UTC):
Please have a look at this fiddle. It's using the directive approach and I think that's the best solution to the problem.
angular.module('demoApp', ['ngSanitize'])
.controller('mainCtrl', MainCtrl);
function MainCtrl() {
var vm = this;
vm.myReplace = function(item) {
return item.replace(/ /g, ' ');
};
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-sanitize/1.5.6/angular-sanitize.js"></script>
<div ng-app="demoApp" ng-controller="mainCtrl as ctrl">
<span ng-bind-html="ctrl.myReplace('This is spaced')"></span>
</div>
Found a way to get the job done:
<select name='Leerling' id='Leerling' size='1'>
<option value='Maak een keuze...' selected disabled>Maak een keuze...</option>
<option ng-repeat="leerlingOption in leerlingController.leerlingen"
ng-bind-html="leerlingController.myReplace(leerlingOption.leerlingdropdown)"
value={{leerlingOption.leerlingdropdown}}></option>
</select>
with myReplace being (as answered by AWolf):
vm.myReplace = function(item) {
return $sce.trustAsHtml(item.replace(/ /g, ' '));
}

multiple inputs based on array

My angular experience is basically about 3 days part time, so there's probably something simple I'm missing here.
I'm trying to create a dynamic list of multiple inputs based on an array, which I then want to reference from elsewhere in the app. What I've tried is loading a template from a custom directive, then $compile-ing it.
<input data-ng-repeat="term in query" data-ng-model="term">
My controller contains $scope.query = [""] which successfully creates the first empty input box. But the input box doesn't seem to update $scope.query[0] when I modify it. This means that when I try to create another empty input box with $scope.query.push(""); (from a keypress listener looking for the "/" key) I get a "duplicates not allowed" error.
I've tried manually listening to the inputs and updating scope.$query based on their value, but that doesn't feel very "angular", and results in weird behaviour.
What do I need to do to link these values. Am I along the right lines or way off?
I made a simple jsfiddle showing how to use an angular model (service) to store the data. Modifying the text inputs will also modify the model. In order to reference them somewhere else in your app, you can include TestModel in your other controllers.
http://jsfiddle.net/o63ubdnL/
html:
<body ng-app="TestApp">
<div ng-controller="TestController">
<div ng-repeat="item in queries track by $index">
<input type="text" ng-model="queries[$index]" />
</div>
<br/><br/>
<button ng-click="getVal()">Get Values</button>
</div>
</body>
javascript:
var app = angular.module('TestApp',[]);
app.controller('TestController', function($scope, TestModel)
{
$scope.queries = TestModel.get();
$scope.getVal = function()
{
console.log(TestModel.get());
alert(TestModel.get());
}
});
app.service('TestModel', function()
{
var queries = ['box1','box2','box3'];
return {
get: function()
{
return queries;
}
}
});

how to avoid double encoding with $sce

Angular $sce service seems to be encoding characters and not trusting the html. Is there an option to have the html trusted?
$scope.text = $sce.trustAsHtml('it's broken')
An example.
<p>it's working</p>
<p>{{ text }}</p>
Looks like.
it's working
it's broken
I'd rather not use ng-bind-html because it's meant to be used in a filter like the following.
{{ text | render }}
It is not the $sce that encode your html, actually nothing does that.
But when you use an interpolation {{ text }}, angular will detect that and replace it with a correct value via textNode.nodeValue, not something like innerHTML. Therefore, your ' will be treated as a normal text, not an encoded HTML entity.
That's why the ng-bind-html exists, and nothing prevent you from using the filter inside the ng-bind-html expression.
<div ng-bind-html="text | render | trustAsHtml"></div>
Example filters:
.filter('render', function () {
return function (value) {
return value + '!';
};
})
.filter('trustAsHtml', function ($sce) {
return function (value) {
return $sce.trustAsHtml(value);
};
})
Example Plunker: http://plnkr.co/edit/F8OQvoSzOR06TPepc2Fo?p=preview

ng-bind-html strips elements attributes

I'm trying to interpolate a string that contains some markup in a template.
In the controller:
$scope.message = "Hello moto <a ui-sref='home.test'>click</a>";
Template:
<div ng-bind-html="message.text"></div>
which renders as:
<div ng-bind-html="message.text" <div="" class="ng-binding">Hello moto <a>click</a></div>
Trying to use the following filter does not help either; the text is simpy escaped for either of the commented choices:
angular.module('test-filters', ['ngSanitize'])
.filter('safe', function($sce) {
return function(val) {
return $sce.trustAsHtml(val);
//return $sce.trustAsUrl(val);
//return $sce.trustAsResourceUrl(val);
};
});
How can I interpolate my string without escaping it nor stripping attributes?
Edit: Plunker http://plnkr.co/edit/H4O16KgS0mWtpGRvW1Es?p=preview (updated with sylwester's version that has reference to ngSanitize
Let have a look here http://jsbin.com/faxopipe/1/edit it is sorted now.
It didn't work because there was another directive inside a tag 'ui-sref',
so you have to use $sce service.
in your js please add method:
$scope.to_trusted = function(html_code) {
return $sce.trustAsHtml(html_code);
and in view :
<p ng-bind-html="to_trusted(message)"></p>
In scenario where you are using ui.router path you must need to use $compile in combination with $sce for your dynamic html so that ui-sref work properly. If you don't do that you'll just see a Link which actually do not work.
e.g <span> Hello moto <a ui-sref='home.test'> Link </a> </span>
//You must need to add boundary conditions, this is just for demonstration
$scope.to_trusted = function(someHTML) {
var compiledVal = $compile(someHTML)($scope);
var compiledHTML = compiledVal[0].outerHTML;
return $sce.trustAsHtml(compiledHTML);
}
And you use like this,
<p ng-bind-html="to_trusted(message)"></p>
Note that your message has to be a valid HTML starting from "<" so if you pass a non HTML to $compile you'll get jqlite error. I used <span> to handle your case.
You missed reference to angular-sanitize.js and you have inject it as well to angular.app
var app = angular.module('plunker', ['ngSanitize']);
the simplest option in to bind html is ng-bind-html :
<li>link ng-html-bind <div ng-bind-html="message"></div></li>
please see Plunkr

Rendering dynamic HTML(angularjs content) content after ajax call in AngularJS

I am new to Angular getting stuck after making ajax call. How do I render/compile the html content once you inject in DOM so that I can still use the AngularJs functions.
Due to the way my backend is set up I have to get content via ajax ($http). And I am making the app without jQuery. I tried $compile and $apply but didn't work. What am I missing here.
I have the code set up at http://jsfiddle.net/rexonms/RB7FQ/3/ . I want the second div content to have the same properties as the first div.
HTML
<div ng-controller="MyCtrl" class="section">
<input ng-model="contentA">
<div>
And the input is: {{contentA}}
</div>
</div>
<div ng-controller="MyAjax" class="section">
<div id="dumpAjax">
{{ajaxData}}
</div>
<button ng-click=getajax()> Get Ajax</button>
</div>
SCRIPT
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
}
function MyAjax($scope){
var data = '<input ng-model="contentB">{{contentB}}';
$scope.getajax = function(){
$scope.ajaxData = data;
}
}
Thanks in advance.
ng-bind-html-unsafe is not available 1.2 and later verison of angular...
so you should use ng-bind-html which creates a binding that will innerHTML the result of evaluating the expression into the current element in a secure way.
using $scope variable in your string make it unsafe, so you should use $sce.trustAsHtml but this time variables in your string cannot be bind because they will be not compiled...
basically you should compile your string in order to bind your variables. Here comes custom directives you can create a directive which can replace with ng-html-bind...
Writing a custom directive which extends ng-bind-html with some extra functions can be a solution...
here is my PLUNKER
and here is your updated JSFIDDLE with my solution...
Instead of {{ajaxData}}, you should use something like:
<div ng-bind-html-unsafe="ajaxData"></div>
However, you'd still need to set the proper model to bind the contentB and get it working.

Resources