Mustache.js escaping "/" - javascript

I have a simple JSON file as shown below:
{
"products": [
{
"title": "United Colors of Benetton Men's Shirt",
"description": "Cool, breezy and charming – this solid green shirt from United Colors of Benetton is born on the beach. Effortlessly classy, this full sleeved shirt is perfect when worn with faded blue jeans and a pair of shades for a weekend get-together.",
"quantity": "10",
"cost": "3.00",
"brand": "United",
"image": "catalog/images/img2.jpg",
"category": "1",
"popularity": "100"
}
]
}
I am displaying this JSON file using Mustache.js into the template blow:
<table class="product-list">
{{#products}}
<tr>
<td>
<table class="product">
<tr>
<td class="product-image">
<img src"{{image}}" height="150" width="150" />
</td>
<td class="product-details">
<p class="title">{{title}}</p>
<p class="description">{{description}}</p>
<p class="quantity"><b>Quanity Available: </b>{{quantity}}</p>
<p class="cost"><b>Cost: </b>£ {{cost}}</p>
<p class="brand"><b>Brand:</b> {{brand}}</p>
</td>
</tr>
</table>
</td>
</tr>
{{/products}}
</table>
Everything works fine but for some reason the slashes in the image property are escaped due to which the images don't show up.
I've tried escaping slashes in the JSON file by adding a backslash in front of them. But instead of correct path I get this.
catalog\/images\/img2.jpg
I also try disabling HTML escaping by using {{{ image }}} and I get this.
catalog\="" images\="" img2.jpg=\""
How can I display the image property properly?
Can anyone please help me with this?
Edit: JS used to generate the template:
$template = $('#product-template').html();
$renderedHtml = Mustache.render($template, $data);
$('#content').html($renderedHtml);

From what I see it should work with triple mustaches {{{image}}}. You are also missing = after src.
Example fiddle:
var jsn = {
"products": [{
"title": "United Colors of Benetton Men's Shirt",
"description": "Cool, breezy and charming – this solid green shirt from United Colors of Benetton is born on the beach. Effortlessly classy, this full sleeved shirt is perfect when worn with faded blue jeans and a pair of shades for a weekend get-together.",
"quantity": "10",
"cost": "3.00",
"brand": "United",
"image": "http://static.cilory.com/26111-large_default/united-colors-of-benetton-men-white-t-shirt.jpg",
"category": "1",
"popularity": "100"
}
]
};
var t = document.getElementById('template').innerHTML;
var m = Mustache.to_html(t, jsn);
document.getElementById('res').innerHTML = m;
console.log(m);
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.7.2/mustache.min.js"></script>
<script id="template" type="text/template">
<table class="product-list">
{{#products}}
<tr>
<td>
<table class="product">
<tr>
<td class="product-image">
<img src="{{{image}}}" height="180" width="150" />
</td>
<td class="product-details">
<p class="title">{{title}}</p>
<p class="description">{{description}}</p>
<p class="quantity"><b>Quanity Available: </b>{{quantity}}</p>
<p class="cost"><b>Cost: </b>£ {{cost}}</p>
<p class="brand"><b>Brand:</b> {{brand}}</p>
</td>
</tr>
</table>
</td>
</tr>
{{/products}}
</table>
</script>
<div id="res"></div>

override the mustache.js escape function to not escape texts:
mustache.escape = function (text) {
return text;
};

Related

How to convert String into a HTML element in Next JS Applcation?

I have saved the product description as the HTML elements into a Database like this. But when I am rendering this data into div, this is displaying as String. I want to display all the data like HTML elements in my Next JS application. I tried JSON.parse, but it's not working.
If someone can help me to fix this will be appreciated.
{
"images": [
{
"alternativeText": "cinnamon",
"path": "public/uploads/5585.jpg"
}
],
"_id": "606c39c884372a0e20c3f9bb",
"name": "Cinnamon",
"code": "5586",
"price": 49,
"category": {
"_id": "6064b37855bd0f26e0df4616",
"name": "Natural Essential Oils",
"createdAt": "2021-03-31T17:38:00.066Z",
"updatedAt": "2021-03-31T17:38:24.398Z",
"__v": 0
},
"description": "<p>Cinnamon Bark Vitality™ essential oil has a warm, spicy flavor that complements a variety of classic culinary treats and drinks. Cinnamon Bark Vitality is not only great for elevating dishes, but it can also be taken as a dietary supplement and is an important ingredient in some of Young Living’s most popular products, including Thieves® Vitality™ and Inner Defense™. Cinnamon Bark Vitality’s warm taste and nostalgic notes bring a spicy addition to your favorite dishes. By using Cinnamon Bark Vitality as a dietary supplement, you can help support healthy digestive and immune systems.</p>",
"createdAt": "2021-04-06T10:36:56.440Z",
"updatedAt": "2021-04-06T10:36:56.440Z",
"__v": 0
}
Check the image attatchement.
Next Js application code
const Product = ({product}) => {
return (
<Fragment>
<Head>
<title>Product</title>
</Head>
<Layout>
<div className="container-fluid product-page">
<div className="page-body">
<div className="row product">
<div className="col-xl-5 col-lg-5 image-box">
<div className="preview-image">
<div className="image">
<img
src={ImageRootPath + "/" + product.images[0].path}
alt={product.images[0].alternativeText}
/>
</div>
</div>
</div>
<div className="col-xl-7 col-lg-7 info-box">
<div className="product-info">
<div className="product-name">
<h4>{product.name}</h4>
<p>{"Product code: " + product.code}</p>
<hr/>
</div>
<div className="product-price">
<h5>Price: <span>{product.price + "$"}</span></h5>
<p>{"Quantity: 5ml"}</p>
</div>
<div className="product-des">
{product.description}
</div>
</div>
</div>
</div>
</div>
</div>
</Layout>
</Fragment>
);
}
As you want to display raw HTML, so this
<div className="product-des">
{product.description}
</div>
should be changed to
<div className="product-des" dangerouslySetInnerHTML={{ __html: product.description }}>
This is covered in the official doc
dangerouslySetInnerHTML is React’s replacement for using innerHTML in the browser DOM [...] you have to type out dangerouslySetInnerHTML and pass an object with a __html key
And you also have to be mindful of the risky to set raw HTML in the case like this
In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack

Adding some logic in v-for with v-if Vue

I have some json with below results
{
"module": [
{
"id": 1,
"title": "Module 1",
"type": "URL",
"size": 1,
"image": "https://localhost/image1.png"
},
{
"id": 2,
"title": "Module 2",
"type": "YOUTUBE",
"size": 2,
"image": "https://localhost/image2.png"
}
]
}
Now i want to render it on a page with some loop and conditional, like below
<template>
<section class="page-section homescreen mt-4">
<div class="container">
<div class="row">
<div class="col-lg-3" v-bind:key="data.index" v-for="data in modules" v-if="data.size == 1">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
<div class="col-lg-6" v-bind:key="data.index" v-for="data in modules" v-if="data.size == 2">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
</div>
</div>
</section>
</template>
<script>
export default {
data() {
return {
modules: [
{
"id": 1,
"title": "Module 1",
"type": "URL",
"size": 1,
"image": "https://localhost/image1.png"
},
{
"id": 2,
"title": "Module 2",
"type": "YOUTUBE",
"size": 2,
"image": "https://localhost/image2.png"
}
]
};
}
};
</script>
But instead of success, i got some error saying
5:99 error The 'modules' variable inside 'v-for' directive should be
replaced with a computed property that returns filtered array instead.
You should not mix 'v-for' with 'v-if' vue/no-use-v-if-with-v-for
8:99 error The 'modules' variable inside 'v-for' directive should be
replaced with a computed property that returns filtered array instead.
You should not mix 'v-for' with 'v-if' vue/no-use-v-if-with-v-for
Actually i want to create the <div class="col-lg-3"> part to be dynamic based on the json, if size:1 mean to have col-lg-3 and if size:2 mean to have col-lg-6
Any explanation and suggestion will be appreciated.
Thank you
eslint-plugin-vue was telling you to do this:
<div class="col-lg-3" v-bind:key="data.index" v-for="data in modules.filter(o=>o.size == 1)">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
<div class="col-lg-6" v-bind:key="data.index" v-for="data in modules.filter(o=>o.size == 2)">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
In your case, it can be simplified as
<div :class="'col-lg-'+data.size*3" v-bind:key="data.index" v-for="data in modules">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
If it's essentially something with css classes, why don't you use v-bind:class or :class with your condition ?
https://v2.vuejs.org/v2/guide/class-and-style.html
But like said in the error message you'll certainly have to create a sub component and then use props on it
https://v2.vuejs.org/v2/guide/components-props.html
In case you have just two sizes:
You can use Computed Properties to achieve this requirement.
First, create two new computed properties like:
computed: {
modulesSize1: function() {
return this.modules.filter(x => x.size == 1)
},
modulesSize2: function() {
return this.modules.filter(x => x.size == 2)
}
}
Now, you can easily loop through computed properties modulesSize1 && modulesSize2 like:
<div class="row">
<div class="col-lg-3" v-bind:key="data.index" v-for="data in modulesSize1" >
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
<div class="col-lg-6" v-bind:key="data.index" v-for="data in modulesSize2" >
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
</div>
In case you have multiple sizes:
First, create a simple method like:
methods: {
getClass: function(size) {
return `col-lg-${size * 3}`
},
}
and then we can update template and use Class Bindings like:
<div :class="getClass(data.size)" :key="data.index" v-for="data in modules">
<img class="img-fluid" :src="`${data.image}`" :alt="`${data.title}`" />
</div>
The v-if is essentially baked in to the v-for (if modules is empty nothing will render) so it's recommended not to use them in combination. If you need it for a separate condition, like you do here, then you'll have to move your v-for on to the <img> itself.
You also won't be able to use data.size this way so you'd have to use something like v-if="modules[0].size == 1" etc.
Edit
#Palash answer is probably the more efficient way to solve this.
Edit 2
#r0ulito and #xianshenglu also makes a really good point, if it's just a class issue, use v-bind.

How to get angular js expressions to consider css values from the api and apply it to its card

I'm creating pokemon cards that take data from the API. How can I get the CSS of a particular card get applied to its respective card from the API directly just like the information which I've rendered using angular-js.
I'm done retrieving the data like name, description and image.I used angular-js directives to get the data.Similarly, the API consists of CSS styling for each of their respective cards.How can I get the CSS of a particular card get applied to its respective card from the API directly just like the information which I've rendered using angular-js.
JSON:
[{
"cardColors": {
"bg": "#47C67B",
"imgbg": "#80EDAC",
"tagbg": "#8edbae",
"text": "#ffffff",
"textbg": "#66CF91"
},
"description": "Bulbasaur is a small quadruped Pokemon that has turquoise skin with darker teal patches ",
"name": "Bulbasaur",
"sprite": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png",
"tag": "Grass"
}, {
"cardColors": {
"bg": "#f88321",
"imgbg": "#ffb047",
"tagbg": "#fab275",
"text": "#ffffff",
"textbg": "#f99847"
},
"description": "Pikachu is a Mouse Pokemon and the evolved form of
Pichu. Pikachu's tail is sometimes struck by lightning as it raises it to
check its surroundings.",
"name": "Pikachu",
"sprite": "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/25.png",
"tag": "Electric"
}]
JS:
var app = angular.module('myApp', []);
app.controller('pokemonCtrl', function($scope, $http) {
$http.get("pokemondata.json").then(function (response) {
$scope.myData = response.data;
});
});
HTML:
<div class="container" ng-app="myApp" ng-controller="pokemonCtrl">
<div class="row">
<div class="col-sm-4" ng-repeat="x in myData">
<h4>{{x.name}}</h4><br/>
<p>{{x.description}}</p><br/>
<img class="cards" ng-src="{{x.sprite}}"><br/>
</div>
</div>
</div>
You should use ngStyle to apply styles from your controller data to your list elements. Something like:
<div class="row">
<div class="col-sm-4" ng-repeat="x in myData" ng-style="{'background-color': x.bg, color: x.text}">
<h4>{{x.name}}</h4><br/>
<p ng-style="{'background-color': x.textbg}">{{x.description}}</p><br/>
<img class="cards" ng-src="{{x.sprite}}"><br/>
</div>
</div>

Displaying array object in ng-repeat angularjs

I have a simple json load list which uses angular directive to render the data from local json.
I wanted to display likes in a separate column and dislikes in the separate column. but I tried the below code snippet, but achieved likes in first column but not sure how to render dislikes in the second column.
Here is the HTML
<ul class="nav">
<li class="active" ng-repeat="item in artists.People">
<a href ng-click='setSelectedArtist(item)'>{{item.name}}
</a>
</li>
</ul>
<!-- Displaying table -->
<table>
<tr>
<th>Likes</th>
<th>Dislikes</th>
</tr>
<tr ng-repeat = "favourites in items.Likes">
<td>{{ favourites }}</td>
/* stuck here */
</tr>
</table>
JSON:
{
"People":[
{
"name":"Andrew Amernante",
"rating":3,
"img":"http://www.fillmurray.com/200/200",
"Description":"Gluten­free cray cardigan vegan. Lumbersexual pork belly blog, fanny pack put a bird on it selvage",
"Likes":[
"Dogs",
"Long walks on the beach",
"Chopin",
"Tacos"
],
"Dislikes":[
"Birds",
"Red things",
"Danish food",
"Dead Batteries"
]
},
{
"name":"Frank Wang",
"rating":5,
"img":"http://www.fillmurray.com/200/201",
"Description":"Before errors, mails were only pressures. This is not to discredit the idea that a magic is the prose of anelizabeth. This could be, or perhaps some posit the outmost coil to be less than dedal. Some assert that those treatments are nothing more than carp.",
"Likes":[
"Frank",
"Manchester United",
"Football",
"Programming"
],
"Dislikes":[
"Dogs",
"Long walks on the beach",
"Chopin",
"Tacos"
]
}
]
}
Controller:
$http.get('people.json').success(function(response) {
$scope.artists = response;
});
$scope.setSelectedArtist = function(artist) {
$scope.items = artist;
};
This code will work even when the lengths of Likes and Dislikes are not equal
<table>
<thead>
<th>Likes</th>
<th>Dislikes</th>
</thead>
<tbody ng-repeat="items in test.People">
<tr ng-repeat="i in range(items.Likes.length, items.Dislikes.length) track by $index">
<td>{{items.Likes[$index]}}</td>
<td>{{items.Dislikes[$index]}}</td>
</tr>
</tbody>
</table>
$scope.range = function(a,b) {
var n = Math.max(a,b);
return new Array(n);
};
Sample JSON
{
"People":[
{
"name":"Andrew Amernante",
"rating":3,
"img":"http://www.fillmurray.com/200/200",
"Description":"Gluten­free cray cardigan vegan. Lumbersexual pork belly blog, fanny pack put a bird on it selvage",
"Likes":[
"Dogs",
"Long walks on the beach",
"Chopin",
"Tacos"
],
"Dislikes":[
"Birds",
"Red things",
"Danish food",
"Batteries",
"Football",
"Dead Batteries"
]
},
{
"name":"Frank Wang",
"rating":5,
"img":"http://www.fillmurray.com/200/201",
"Description":"Before errors, mails were only pressures. This is not to discredit the idea that a magic is the prose of anelizabeth. This could be, or perhaps some posit the outmost coil to be less than dedal. Some assert that those treatments are nothing more than carp.",
"Likes":[
"Frank",
"Manchester United",
"Football",
"Programming",
"Dead Batteries"
],
"Dislikes":[
"Dogs",
"Long walks on the beach",
"Chopin",
"Tacos"
]
}
]
}
Output:
Sample output
Try the following:
<tr ng-repeat = "favourites in items.Likes">
<td>{{ favourites }}</td>
<td ng-if="$index <= items.Dislikes.length-1">{{items.Dislikes[$index]}}</td>
</tr>
try this code :
<table ng-repeat="items in artists.People">
<tr>
<th>Likes</th>
<th>Dislikes </th>
</tr>
<tr ng-if="items.Likes.length <= items.Dislikes.length" ng-repeat="d in items.Dislikes track by $index">
<td>{{d}}</td>
<td ng-if="items.Likes[$index]">{{items.Likes[$index]}}</td>
</tr>
<tr ng-if="items.Likes.length > items.Dislikes.length" ng-repeat="d in items.Likes track by $index">
<td>{{d}}</td>
<td ng-if="items.Dislikes[$index]">{{items.Dislikes[$index]}}</td>
</tr>
</table>

How to use ng-repeat in a nested json in an ionic project

I'm trying to use ng-repeat in a nested json object.
{
"title": "Important message 01",
"img": "any url image here",
"authorPhoto": "http://lorempixel.com/40/40/people/4/",
"author": "John Doe",
"datePosted": "1 day ago",
"thumbsUp": "245",
"thumbsDown": "200",
"commentsNum": "123",
"id": "1",
"comments": [
"comment",
{
"authorCommentPhoto": "http://lorempixel.com/40/40/people/5/",
"author": "Jimmy doe",
"text": "useless commment",
"dateCommented": "01/08/2016"
}
]
}
I can list the top level json (title, img, etc...), but I do know how to list the comments part
<ion-item ng-repeat="card in cards" href="#/app/playlists/{{card.id}}" class="card-wrapper">
<div class="card" style="background: url({{card.img}}); background-size:100%;">
<div class="inner-wrapper">
<img ng-src="{{card.authorPhoto}}" alt="Author profile photo">
<p class="author">{{card.author}} <br>
{{card.datePosted}}
</p>
<p class="essay">{{card.title}}</p>
<div class="footWrapper">
<div class="thumbsUp"><i class="icon ion-arrow-up-c"></i>{{card.thumbsUp}}</div>
<div class="comments">{{card.commentsNum}}</div>
<div class="thumbsDown"><i class="icon ion-arrow-down-c"></i>{{card.thumbsDown}}</div>
</div>
</div>
</div>
<div class="commentsWrapper">
<div class="head">
<img class="profilePhoto" src="http://tilomitra.com/wp-content/uploads/2014/08/avatar-cartoon.png" alt="avatar photo">
<input type="text" placeholder="Write a comment...">
</div>
<div class="commentsContainer">
<ul>
<li ng-repeat="comment in cards.comments">
{{comment.authorCommentPhoto}} <br>
{{comment.author}} <br>
{{comment.text}} <br>
{{comment.dateCommented}}
</li>
</ul>
</div>
</div>
</ion-item>
How can I solve this ?
The comments array has a string and an object. Remove the string "comments" and just use an array of objects. Then use ng-repeat="comment in card.comments"
{
"comments":[
{
"authorCommentPhoto": "http://lorempixel.com/40/40/people/5/",
"author": "Jimmy doe",
"text": "useless commment 1",
"dateCommented": "01/08/2016"
},
{
"authorCommentPhoto": "http://lorempixel.com/40/40/people/5/",
"author": "Jimmy doe",
"text": "useless commment 2",
"dateCommented": "01/09/2016"
}
]
}

Categories

Resources