I am using Angular for front end, and node for back end. I am getting the data from a mySql db, where I have manually stored it in text format but with HTML tags on it i.e:
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
The data is currently in JSON format i.e:
{
"data": [
{
"id": 1,
"sort_order": 0,
"content_type": "main_message",
"heading": "Welcome to our site ",
"content": "<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>",
"page_name": "home",
"author_id": "abhatti",
"date_created": "2017-03-13T15:12:00.000Z",
"date_modified": "2017-03-13T15:12:00.000Z",
"modified_by": "abhatti"
},
{
"id": 2,
"sort_order": 0,
"content_type": "main_body_content",
"heading": "Announcements",
"content": "",
"page_name": "home",
"author_id": "Robert",
"date_created": "2016-12-31T17:00:00.000Z",
"date_modified": "2017-03-11T07:08:00.000Z",
"modified_by": "Danny"
},
when I put the data in the table , I want the table to show the data in HTML format , but it shows in raw format with all the HTML tags visible on the page like this
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
but I want something like this
item1
item2
item3
How can I convert the data properly so it is read by the browser as HTML? Right now it is put in as a string.
By default AngularJS (1.2+) will interpolate HTML as text.
This function is built into AngularJS to avoid XSS concerns, however there are times (such as in your case here) where you may actually want to render HTML in your template instead of displaying it as text.
To do so, take a look at AngularJS' $sce library. In your controller you can specify that you want to trust the data you retrieved from MySQL as HTML:
$scope.explicitlyTrustedHtml = $sce.trustAsHtml('<div><span>Hello World!</span></div>');
In your template be sure to bind using ng-bind-html:
<div ng-controller="MyController as myCtrl">
<div ng-bind-html="myCtrl.explicitlyTrustedHtml"></div>
</div>
If you absolutely need to, you can disable $sce for the entire application, however this is highly discouraged for security purposes. To do so inject $sceProvider, add the following line to your main module's configuration block:
$sceProvider.enabled(false);
Although the $sce library is helpful, my advice would be to find a better way to restructure your data in MySQL so that you're not asking it for HTML. If you're only ever reading the data -- you might be okay from a security perspective. However, if you're allowing users to POST HTML snippets from your AngularJS application and are persisting these snippets in MySQL, you're asking for XSS attacks.
Related
I started building an application with the Vue CLI, and I have the following code snippet in a component:
<template>
<div v-loading="loading">
<el-carousel :interval="4000" type="card" height="350px">
<el-carousel-item v-for="element in persons" :key="element.id">
<div class="testimonial-persons">
<el-avatar :size="80">
<img :src="require('#assets/testimonial/'+ element.photo)">
</el-avatar>
<h3>{{element.name}}</h3>
<h4>{{element.occupation}}</h4>
<hr style="width:50%;">
<p>"{{element.comment}}"</p>
</div>
</el-carousel-item>
</el-carousel>
</div>
</template>
When the page is loaded I make a request for an API that returns an array of objects that I store in persons to iterate over the template.
Persons
[
{
"testimonial_id": "2",
"persons_id": "1",
"id": "1",
"name": "Tom lima",
"occupation": "CEO / Pugmania",
"comment": "Simply the best customer service and attention to detail.",
"photo": "20200320193143R7pChVea3IkmujRRmS.png"
},
]
Everything works normally, the problem is with the image loading.
When I enter the image name manually it works.
<img src="#assets/testimonial/20200320193143R7pChVea3IkmujRRmS.png">
Does anyone have any idea how to solve?
Your template is correct except that you're missing a / following the #. It should be:
<img :src="require('#/assets/testimonial/' + element.photo)">
This would be needed for the manual usage too, so maybe you left it out when you converted it to a dynamic path.
I got it working excellent with one template but ran into an issue trying to replace my inner ng-repeat with another template. Kind of like grouped data or more like nested data.
so let me simplify my html here:
<div data-ng-controller="index.dataGridController" data-ux-datagrid="index.items" class="listA datagrid" data-addons="whichTemplate" grouped="'focus'">
<script type="template/html" data-template-name="default" data-template-item="item">
<div>
<h3>{{ item.obj.name }}</h3>
<!--- instead of
<ul>
<li ng-repeat="listItem in item.focus>{{listitem}}</li>
</uL
-->
</div>
</script>
<script type="template/html" data-template-name="innerFocus" data-template-item="item">
<div>
<ul>
<li>{{item.focus.id}}</li>
</ul>
</div>
</script>
</div>
and the index.items look like this:
[{
"obj": {
"name": "someName"
}
"focus": [
{"id": "something here"},
{"id": "Another etc"}
]
}]
// which template is basically copy and pasted from examples
angular.module('ux').factory('whichTemplate', function () {
return function (inst) {
// now we override it with our method so we decide what template gets displayed for each row.
inst.templateModel.getTemplate = function (item) {
var name = item.focus ? 'innerFocus' : 'default';
// now we get the template from the name.
return inst.templateModel.getTemplateByName(name);
};
};
});
Trying to iterate a list with the focus array. Any ideas? I think it would make for a great example in the docs. Adding a fiddle. http://jsfiddle.net/uftsG/88/
Instead of putting all focus array in one li i'm trying to get them spread out while also having the item.obj.name above the list.
I am not familiar with ux-data grid. If you are set on using it, you can ignore this answer, but I did a small search engine (purely for academic reasons) and i ended up using ng-grid to display the data. I followed the github documentation and ended up boot-strapping #scope.myDefs with the data I needed on the backend using a $scope.getMyData function. In the view all you really need to do is add input fields to get the data, and then a div class with your ng-grid. It's super cool because it ensures the code is modular, and there are no funky functions going on in the view with nested ng-repeats so on and so forth. The only part that gave me trouble was the CSS because I'm not bootstrap savvy yet :) Here's some docs if you end up interested in ng-grid at all.
http://angular-ui.github.io/ng-grid/
The handlebars data shows up fine on the static page, but the problem is I also have a modal, and the data is not being populated correctly on the modal.
I am using the avgrund modal (you can view the Codepen here)
main.js - handlebars code
var projectData = [
{
id: "0",
name: "Jack",
},
{
id: "1",
name: "Sally",
},
];
var theTemplateScript = $("#project-template").html();
var theTemplate = Handlebars.compile(theTemplateScript);
$("#content").append(theTemplate(projectData));
index.html
<div id="content">
<script id="project-template" type="x-handlebars-template">
<div class="pile">
{{#each this}}
<a onclick="avgrund.activate( 'stack' );">
<div class="box box{{id}}">
<span class="project_name project_name{{id}}">{{name}}</span>
</div>
</a>
<aside class="avgrund-popup">
<h2>{{name}}</h2>
<p>
You can hit ESC or click outside to close the modal. Give it a go to see the reverse transition.
</p>
</aside>
{{/each}}
</div>
</script>
</div>
Problem
The div boxes will show up fine, but whenever I click the boxes so that the modal appears, the modal only displays the last element in projectData.
I've been able to have the data appear fine when I use bootstrap modals, but for some reason not the avgrund modal.
Hint at a possible solution?
I think the answer to this StackOverflow q: how to populate hidden form field hints as something that might work, e.g. pulling out the data and re-inserting it in the avgrund modal code, as such
var data = {
"Value": [
{"Id": "6b7", "Notes": "testing", "CreatedBy": "User1"},
{"Id": "6b7", "Notes": "Testing 1", "CreatedBy": "User2"}
]};
data.Id = data.Value[0].Id;
var tmpl = Handlebars.compile($('#template').html());
var html = tmpl(data);
But I don't fully understand the answer and wasn't able to get it to work. Could someone point to some approaches or guiding principles that might be helpful?
Here's a fiddle that shows a working example: http://jsfiddle.net/9f9w1trs/
As pointed out by Roamer-1888 you had an extra closing </div> in there. You didn't include the code that actually compiles the template and populates it.
The basic idea is that you define a template - like you did
<script id="project-template" type="x-handlebars-template"> ....</script>
Then you "compile" the template (you can pre-compile them for performance reasons or if you'd like to only use the lightweight run-time library opposed to the full library).
var source = $("#project-template").html();
var template = Handlebars.compile(source);
and then you can populate your template with data ...
var populatedHtml = template(projectData);
and finally you add your populated HTML to the DOM
$('#myContent').append(populatedHtml);
Handlebars doesn't really care if you add it to a hidden div or not - it just replaces contents between {{}} ;)
I'm currectly working on a Wordpress project. But for a nice change I'm working with a JSON API, which only gives me the information I need.
I'm only facing one problem at the moment. The content part in my JSON contains HTML tags, which get printed on the screen, without actually using the HTML tags.
The JSON output looks like this:
[{
"ID": 11,
"title": "test",
"status": "publish",
"type": "page",
"author": {
"ID": 1,
"name": "admin",
"slug": "admin",
"URL": "",
"avatar": "http:\/\/0.gravatar.com\/avatar\/401f2b3c91dee8969b193544c3d9a636&d=404&r=G",
"meta": {
"links": {
"self": "http:\/\/geertvandelangenberg.nl\/wp\/wp-json.php\/users\/1",
"archives": "http:\/\/geertvandelangenberg.nl\/wp\/wp-json.php\/users\/1\/posts"
}
}
},
"content": "<p>testtt<\/p>\n",
}]
My HTML looks like this:
<script src="http://geertvandelangenberg.nl/wp/wp-content/themes/twentythirteen/js/angular.min.js"></script>
<script>
function PostsCtrlAjax($scope, $http) {
$http({method: 'GET', url: 'http://geertvandelangenberg.nl/wp/wp-json.php/pages/'}).success(function(data) {
$scope.posts = data; // response data
});
}
</script>
<div id="ng-app" ng-ap- ng-controller="PostsCtrlAjax">
<div ng-repeat="post in posts">
<h2>
<a href='{{post.link}}'>{{post.title}}</a>
</h2>
<div class="time">
{{post.date}} - {{post.author.name}}
</div>
<p>{{post.content}}</p>
</div>
</div>
Could anyone tell me how I can filter out the HTML tags in the JSON object?
Thanks in advance!
Geert
EDIT
Thanks for you comments so far, could anyone please edit this jsbin, I can't seem to manage to get this to work, even with the AngularJS docs. I'm still quite noobish with Angular, but if someone would help me, it'd be much appreciated :)
jsbin.com/oRoqIJEC/1/edit
PS. output does not work on jsbin because of stupid Access-Control-Allow-Origin issues..
ng-bind-html will render your HTML. Don't forget to inject ngSanitize into your controller though.
I am searching for something which renders an HTML template starting from a JSON file of data.
The matter is that the plugin/framework/library I'm searching for must create itself the <html> template structure, starting from something very simple.
For example I have an simple html like this:
<ul>
<li><li>
</ul>
and a json like this:
{
"mylist":{
"listone":
{"img" : "/img/pippo.gif" ,
"text1" : "pluto",
"text2" : "topolino",
"link" : "http://www.sito.it"
},
"listtwo":
{"img" : "/img/pippo.gif" ,
"text1" : "pluto",
"text2" : "topolino",
"link" : "http://www.sito.it"
}
}
}
and I want the data to render in my document like this:
<ul>
<li>
<img src="/img/pippo.gif" />
<h1>pluto</h1>
<p><a href="http:://www.sito.it>topolino</a></p>
</li>
</ul>
If I head already the entire structure I could use pure.js as usual, but, since I don't have the inner tags in the li, can I inject the HTML code with the pure.js directives?
Or is it possible only with JsRender or similar?
Pure JS allows you to use JavaScript function with directives. Whatever is returned from that function, will be used as a value for a directive.
The argument of the function is an object with the following
properties:
context : This is the full JSON that was passed for transformation
item* : the current loop item
items* : all the items of the loop
pos* : the current position in the loop. An integer when iterating an array, a property name iterating on a collection
The following example shows how to do it.
var data = {
"img": "/img/pippo.gif",
"text1": "pluto",
"text2": "topolino",
"link": "http://www.sito.it"
}
var directive = {
'li': function (arg) {
return "<img src=\""+arg.context.img+"\" /><h1>"
+arg.context.text1+"</h1><p><a href=\""
+arg.context.link+"\">"+arg.context.text2+"</a></p>"
}
}
$('ul').render(data, directive);
The given HTML:
<ul><li></li></ul>
Will become as following one (after rendering):
<ul>
<li>
<img src="/img/pippo.gif">
<h1>pluto</h1>
<p>
topolino
</p>
</li>
</ul>
I hope that will help.
This is more advise than answer. I would recommend against what you are trying to accomplish. The powerful concept used for templating is to separate the HTML from the code. When you keep this separation and you can figure out how to write code and understand code that follows this separation. Then code will be easier to write and to understand, not only by you but by others that follow that same principle.
In your example your HTML template should be like this:
<ul>
<li>
<img src="/img/pappo.gif" />
<h1>marte</h1>
<p><a href="http:://www.sito.it>guille</a></p>
</li>
</ul>
and a json like this:
{
"mylist":{
"listone":
{"img" : "/img/pippo1.gif" ,
"text1" : "pluto1",
"text2" : "topolino1",
"link" : "http://www.sito1.it"
},
"listtwo":
{"img" : "/img/pippo2.gif" ,
"text1" : "pluto2",
"text2" : "topolino2",
"link" : "http://www.sito2.it"
}
}
}
and the final should look like this:
<ul>
<li>
<img src="/img/pippo1.gif" />
<h1>pluto1</h1>
<p><a href="http:://www.sito1.it>topolino1</a></p>
</li>
<li>
<img src="/img/pippo2.gif" />
<h1>pluto2</h1>
<p><a href="http:://www.sito2.it>topolino2</a></p>
</li>
</ul>
The easiest way I can explain how to accomplish this is to make your JSON data structure follow your HTML almost one to one. The huge difference is that once that is done the template will be easy to write, and programming the JSON transformation will eventually be easier than writing the HTML transformation. Plus your HTML templates will be 100% render-able by a browser and a 100% modifiable by non programmers. The key here is that although your final product is HTML, taking the JSON object route will produce better code. It won't remove the actual problem of creating the JSON, and you will need to adjust, learn and find tools to do that.
Certainly it's possible. Search for 'javascript DOM createElement' and you'll find plenty of examples (including all over stackoverflow).